ASR_BASE

Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/marvell/services/audio/libacm/acm/src/ac_thread.c b/marvell/services/audio/libacm/acm/src/ac_thread.c
new file mode 100644
index 0000000..23737bf
--- /dev/null
+++ b/marvell/services/audio/libacm/acm/src/ac_thread.c
@@ -0,0 +1,864 @@
+/*
+ * 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.
+ *
+ */
+
+/*
+ * ac_thread.c: enabled for AUDIO_CALIBRATION only
+ */
+
+#define LOG_TAG "ac_thread"
+//#define LOG_NDEBUG 0
+
+#include <cutils/log.h>
+#include <cutils/properties.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <errno.h>
+
+#include "audioCalibration.h"
+#include "acm_aph.h"
+#include "acm_param.h"
+#include "ac_thread.h"
+#include "vcm.h"
+#include "adsp_ve.h"
+
+#define REG_BUFFER_SIZE 100
+#define PHY_VERSION_LEN 36
+static pthread_t ACM_Calibration_Server;
+
+int NVM_Calibration_IPC(AC_IPC_Package *package);
+void get_msa_gain_by_path_name(const char * out_path_name, const char * path_name, unsigned char volume,
+        signed char *ret_gain, signed char *ret_gain_wb, signed char *ret_sidetone_gain, signed char *ret_sidetone_gain_wb, bool use_extra_vol);
+ACM_ReturnCode AC_ReloadCalibrationData(AC_Digital_Gain *gain);
+void AC_EnablePath(AC_IPC_Package_Body *path_para, AC_Digital_Gain *gain);
+void AC_DisablePath(AC_IPC_Package_Body *path_para);
+void AC_MutePath(AC_IPC_Package_Body *path_para);
+void AC_SetPathVolume(AC_IPC_Package_Body *path_para, AC_Digital_Gain *gain);
+void AC_SwitchPath(AC_IPC_Package_Body *path_para, AC_Digital_Gain *gain);
+
+extern audio_mode_t ACMGetAudioMode(void);
+extern void get_pcm_config(int *p_role, int *p_rate);
+
+static int fd_server = -1;
+static int clientfd_server = -1;
+
+//client which send message to NVM server.
+int NVM_Calibration_IPC(AC_IPC_Package *package)
+{
+    int fd, len, value;
+    struct sockaddr_un   un;
+
+    /* create a UNIX domain stream socket */
+    if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
+        LOGE(NVM_Calibration_IPC, "[Audio NVM Calibration][%s][%d][create socket fail]\n", __FUNCTION__, __LINE__);
+        return 1;
+    }
+
+    /* fill socket address structure with server's address */
+    memset(&un, 0, sizeof(un));
+    un.sun_family = AF_UNIX;
+    switch (package->type)
+    {
+        case AUDIO_NVM_GetGainConfigure:
+        case AUDIO_NVM_ReloadCalibrationData:
+        case AUDIO_NVM_GetVEConfigure:
+            strcpy(un.sun_path, NVM_CALIBRATION_SOCKET);
+            len = offsetof(struct sockaddr_un, sun_path) + strlen(NVM_CALIBRATION_SOCKET);
+            break;
+
+        default:
+            LOGE(NVM_Calibration_IPC, "[Audio NVM Calibration Client][%d][IPC type error]\n", __LINE__);
+            close(fd);
+            return 3;
+    }
+    if (connect(fd, (struct sockaddr *)&un, len) < 0) {
+        LOGE(NVM_Calibration_IPC,"[Audio NVM Calibration Client][%d][connect fail][error %d(%s)]\n", __LINE__,errno, strerror(errno));
+        close(fd);
+        return 4;
+    }
+
+    LOGI(NVM_Calibration_IPC,"[Audio NVM Calibration Client][%d]-[send type:%d]-[d1:%d][d2:%d][d3:%d][d4:%d]\n",
+            __LINE__,
+            package->type, package->body.d1, package->body.d2, package->body.d3, package->body.d4);
+
+    LOGI(NVM_Calibration_IPC,"NVM_Calibration_IPC:: un.sun_path=%s!", un.sun_path);
+
+    if(write(fd, package, sizeof(AC_IPC_Package)) == -1) {
+        LOGE(NVM_Calibration_IPC,"[Audio NVM Calibration Client][%d][write fail]\n", __LINE__);
+        close(fd);
+        return 5;
+    }
+
+    /* get data from server when necessary */
+    switch (package->type)
+    {
+        case AUDIO_NVM_GetGainConfigure:
+            if(read(fd, package->ptr, sizeof(ACMCodec_GainT)) == -1) {
+                LOGE(NVM_Calibration_IPC,"[Audio NVM Calibration Client][%d][read fail]\n", __LINE__);
+                close(fd);
+                return 11;
+            }
+            break;
+
+        case AUDIO_NVM_ReloadCalibrationData:
+            if(read(fd, &value, sizeof(int)) == -1) {
+                LOGE(NVM_Calibration_IPC,"[Audio NVM Calibration Client][%d][read fail]\n", __LINE__);
+                close(fd);
+                return 12;
+            }
+            else {
+                if(value == -1) {
+                    LOGI(NVM_Calibration_IPC,"[Audio NVM Calibration Client][%d][AUDIO_NVM_ReloadCalibrationData Fail: no codec compiled]\n", __LINE__);
+                }
+                else if(value == 0) {
+                    LOGI(NVM_Calibration_IPC,"[Audio NVM Calibration Client][%d][AUDIO_NVM_ReloadCalibrationData Success: reload existing file]\n", __LINE__);
+                }
+                else if(value == 1) {
+                    LOGI(NVM_Calibration_IPC,"[Audio NVM Calibration Client][%d][AUDIO_NVM_ReloadCalibrationData Success: create new file]\n", __LINE__);
+                }
+            }
+            break;
+
+        case AUDIO_NVM_GetVEConfigure:
+            if(read(fd, package->ptr, sizeof(EnhanceParmsT)) == -1) {
+                LOGE(NVM_Calibration_IPC,"[Audio NVM Calibration Client][%d][read fail]\n", __LINE__);
+                close(fd);
+                return 13;
+            }
+            break;
+
+        default:
+            break;
+    }
+
+    close(fd);
+
+    return 0;
+}
+
+// get MSA gain from ACM NVM according to device path name
+void get_msa_gain_by_path_name(const char * out_path_name, const char * path_name, unsigned char volume,
+        signed char *ret_gain, signed char *ret_gain_wb, signed char *ret_sidetone_gain, signed char *ret_sidetone_gain_wb, bool use_extra_vol)
+{
+    int extra_volume = (use_extra_vol ? MSA_GAIN_EXTRA_MODE : MSA_GAIN_NORMAL_MODE);
+    ACM_MsaGain msa_gain = {0};
+    unsigned int size = sizeof(ACM_MsaGain);
+
+    msa_gain.volume = volume;
+    msa_gain.gain = 0;
+    msa_gain.wbGain = 0;
+    msa_gain.path_direction = 0;
+
+    // fix to VC mode here. only VC have msa gain
+    msa_gain.out_path_name = out_path_name;
+    msa_gain.path_name = path_name;
+
+    if (ACMSetParameter(ACM_MSA_GAIN_MODE, NULL, extra_volume) != ACM_RC_OK) {
+        LOGE(get_msa_gain_by_path_name, "set output msa gain mode failed, use the default normal mode ");
+    }
+
+    if (ACMGetParameter(ACM_MSA_GAIN, &msa_gain, &size) != ACM_RC_OK) {
+        LOGE(get_msa_gain_by_path_name, "get output msa gain failed, use default gain.");
+    }
+
+    *ret_gain = msa_gain.gain;
+    *ret_gain_wb = msa_gain.wbGain;
+    *ret_sidetone_gain = msa_gain.sidetone_gain;
+    *ret_sidetone_gain_wb = msa_gain.sidetone_wbGain;
+}
+
+//handle the message from NVM server, and recover the status using new config.
+ACM_ReturnCode AC_ReloadCalibrationData(AC_Digital_Gain *gain) {
+
+    int Rx_path_id = 0xFF;
+    int Tx_path_id = 0xFF;
+    int volume_Rx = 0;
+    int mute_Tx = 0;
+    const char* Rx_pathname = NULL;
+    const char* Tx_pathname = NULL;
+
+    signed char input_gain = 0;
+    signed char input_gain_wb = 0;
+    signed char output_gain = 0;
+    signed char output_gain_wb = 0;
+    signed char rx_sidetone_gain = 0;
+    signed char rx_sidetone_gain_wb = 0;
+    signed char tx_sidetone_gain = 0;
+    signed char tx_sidetone_gain_wb = 0;
+    unsigned char vc_output_vol = 0;
+    bool use_extra_vol = 0;
+
+    //Default: notify audioCalibration.c not to configure DSP gain
+    gain->path_direction_Rx = VCM_PATH_NOT_CONNECTED;
+    gain->path_direction_Tx = VCM_PATH_NOT_CONNECTED;
+
+    ACM_ReloadCalibrationData();
+
+    //get active path
+    ACM_GetEnabledPathId(&Rx_path_id, &Tx_path_id, &volume_Rx, &mute_Tx);
+
+    if ((0xFF == Rx_path_id) || (0xFF == Tx_path_id))
+    {
+        LOGE( AC_ReloadCalibrationData, "%s/L%d: no enabled path.",__FUNCTION__, __LINE__);
+        return ACM_RC_OK;
+    }
+
+    LOGI( AC_ReloadCalibrationData, "%s/L%d: Rx_path_id=%d, Tx_path_id=%d, volume_Rx=%d, mute_Tx=%d.",
+            __FUNCTION__, __LINE__, Rx_path_id, Tx_path_id, volume_Rx, mute_Tx);
+
+    //HIFI has no digital gain
+    if (ACM_RC_OK_VOICE_MATCHED != APHAudioPathCheckPathId(Rx_path_id, Tx_path_id))
+    {
+        LOGI( AC_ReloadCalibrationData, "%s/L%d: current mode is AUDIO_MODE_NORMAL.",__FUNCTION__, __LINE__);
+        return ACM_RC_OK;
+    }
+
+    Rx_pathname = ACM_GetPathName(Rx_path_id);
+    Tx_pathname = ACM_GetPathName(Tx_path_id);
+
+    if ((NULL == Rx_pathname) || (NULL == Tx_pathname))
+    {
+        LOGE( AC_ReloadCalibrationData, "%s/L%d: RX or TX pathname is NULL.",__FUNCTION__, __LINE__);
+        return ACM_RC_OK;
+    }
+
+    vc_output_vol = volume_Rx;
+
+    get_msa_gain_by_path_name(Rx_pathname, Tx_pathname, 100, &input_gain, &input_gain_wb, &tx_sidetone_gain, &tx_sidetone_gain_wb, use_extra_vol);
+    get_msa_gain_by_path_name(Rx_pathname, Rx_pathname, vc_output_vol, &output_gain, &output_gain_wb, &rx_sidetone_gain, &rx_sidetone_gain_wb, use_extra_vol);
+
+    LOGI(AC_ReloadCalibrationData, "%s/L%d: input_gain=0x%x, input_gain_wb=0x%x, output_gain=0x%x, output_gain_wb=0x%x.use_extra_vol=%d.\n",
+            __FUNCTION__, __LINE__, input_gain, input_gain_wb, output_gain, output_gain_wb, use_extra_vol);
+
+    gain->path_direction_Rx = VCM_PATH_OUT;
+    gain->digital_gain_Rx = output_gain | (output_gain_wb << 8);
+    gain->volume_Rx = vc_output_vol;
+
+    gain->path_direction_Tx = VCM_PATH_IN;
+    gain->digital_gain_Tx = input_gain |  (input_gain_wb << 8);
+    gain->volume_Tx = vc_output_vol;
+
+    gain->path_direction_SideTone = VCM_PATH_SIDETONE;
+    gain->digital_gain_SideTone = rx_sidetone_gain |  (rx_sidetone_gain_wb << 8);
+    gain->volume_SideTone = vc_output_vol;
+
+    LOGI(AC_ReloadCalibrationData, "%s/L%d: digital_gain_Rx=0x%x, volume_Rx=%d, digital_gain_Tx=0x%x, volume_Tx=%d, digital_gain_SideTone=%d.\n",
+            __FUNCTION__, __LINE__, gain->digital_gain_Rx, gain->volume_Rx, gain->digital_gain_Tx, gain->volume_Tx, gain->digital_gain_SideTone);
+
+
+    return ACM_RC_OK;
+}
+
+ACM_ReturnCode APHReloadNvm(void) {
+    AC_Digital_Gain gain;
+    ACM_ReturnCode ret;
+
+    LOGI(APHReloadNvm, "%s/L%d: ReloadCalibrationData", __FUNCTION__, __LINE__);
+    memset(&gain, 0x00, sizeof(AC_Digital_Gain));
+
+    ret = AC_ReloadCalibrationData(&gain);
+    if (ACM_RC_OK != ret) {
+        LOGI(APHReloadNvm, "%s/L%d: ReloadCalibrationData fail.", __FUNCTION__, __LINE__);
+        return ret;
+    }
+
+#ifdef PXA1826_AUDIO
+    ret = APHSetMSAGain(&gain);
+    if (ACM_RC_OK != ret) {
+        LOGI(APHReloadNvm, "%s/L%d: ReloadCalibrationData fail.", __FUNCTION__, __LINE__);
+        return ret;
+    }
+#endif
+
+    return ACM_RC_OK;
+}
+
+/*
+Function: enable the path which is disabled status.
+path_para.d1: Rx_path_id
+path_para.d2: Tx_path_id
+path_para.d3: volume
+ */
+void AC_EnablePath(AC_IPC_Package_Body *path_para, AC_Digital_Gain *gain)
+{
+    int Rx_path_id = path_para->d1;
+    int Tx_path_id = path_para->d2;
+    unsigned int Volume = path_para->d3;
+
+    signed char input_gain = 0;
+    signed char input_gain_wb = 0;
+    signed char output_gain = 0;
+    signed char output_gain_wb = 0;
+    signed char rx_sidetone_gain = 0;
+    signed char rx_sidetone_gain_wb = 0;
+    signed char tx_sidetone_gain = 0;
+    signed char tx_sidetone_gain_wb = 0;
+    unsigned char vc_output_vol = 0;
+    bool use_extra_vol = 0;
+
+    const char* Rx_pathname = ACM_GetPathName(Rx_path_id);
+    const char* Tx_pathname = ACM_GetPathName(Tx_path_id);
+
+    if ((NULL == Rx_pathname) || (NULL == Tx_pathname))
+    {
+        LOGE( AC_EnablePath, "%s/L%d: RX or TX pathname is NULL.",__FUNCTION__, __LINE__);
+        return;
+    }
+
+    vc_output_vol = Volume;
+
+    LOGI( AC_EnablePath, "%s/L%d: Rx_path_id =  %d, Rx_pathname =%s,  Tx_path_id =  %d, Tx_pathname = %s, Volume =%d",
+            __FUNCTION__, __LINE__, Rx_path_id, Rx_pathname, Tx_path_id, Tx_pathname, Volume);
+
+    if ((ACM_RC_OK_HIFI_MATCHED != APHAudioPathCheck (Rx_pathname, Tx_pathname))
+            && (ACM_RC_OK_VOICE_MATCHED != APHAudioPathCheck (Rx_pathname, Tx_pathname)))
+    {
+        LOGE( AC_EnablePath, "%s/L%d: RX is not matched with TX.",__FUNCTION__, __LINE__);
+        return;
+    }
+
+    //Disable all enabled path, otherwise there may be several enabled path.
+    APHDisableAllPath();
+
+    ACMAudioPathEnable(Rx_pathname, Volume);
+    ACMAudioPathEnable(Tx_pathname, Volume);
+
+    //get the gain for voice
+    if (ACM_RC_OK_HIFI_MATCHED == APHAudioPathCheck (Rx_pathname, Tx_pathname))
+    {
+        LOGI( AC_EnablePath, "%s/L%d: RX is matched with TX about HIFI. Not need to get digital gain.",__FUNCTION__, __LINE__);
+        return;
+    }
+
+    get_msa_gain_by_path_name(Rx_pathname, Tx_pathname, 100, &input_gain, &input_gain_wb, &tx_sidetone_gain, &tx_sidetone_gain_wb, use_extra_vol);
+    get_msa_gain_by_path_name(Rx_pathname, Rx_pathname, vc_output_vol, &output_gain, &output_gain_wb, &rx_sidetone_gain, &rx_sidetone_gain_wb, use_extra_vol);
+
+    LOGI(AC_EnablePath, "%s/L%d: input_gain= 0x%x, input_gain_wb=0x%x, output_gain=0x%x, output_gain_wb=0x%x.use_extra_vol=%d.\n",
+            __FUNCTION__, __LINE__, input_gain, input_gain_wb, output_gain, output_gain_wb, use_extra_vol);
+
+    gain->path_direction_Rx = VCM_PATH_OUT;
+    gain->digital_gain_Rx = output_gain | (output_gain_wb << 8);
+    gain->volume_Rx = vc_output_vol;
+
+    gain->path_direction_Tx = VCM_PATH_IN;
+    gain->digital_gain_Tx = input_gain |  (input_gain_wb << 8);
+    gain->volume_Tx = vc_output_vol;
+
+    gain->path_direction_SideTone = VCM_PATH_SIDETONE;
+    gain->digital_gain_SideTone = rx_sidetone_gain |  (rx_sidetone_gain_wb << 8);
+    gain->volume_SideTone = vc_output_vol;
+
+    LOGI(AC_EnablePath, "%s/L%d: digital_gain_Rx=0x%x, volume_Rx=%d, digital_gain_Tx=0x%x, volume_Tx=%d, digital_gain_SideTone=%d.\n",
+            __FUNCTION__, __LINE__, gain->digital_gain_Rx, gain->volume_Rx, gain->digital_gain_Tx, gain->volume_Tx, gain->digital_gain_SideTone);
+
+}
+
+/*
+Function: Disable the path which is enabled.
+path_para.d1: Rx_path_id
+path_para.d2: Tx_path_id
+ */
+void AC_DisablePath(AC_IPC_Package_Body *path_para) {
+    int Rx_path_id = path_para->d1;
+    int Tx_path_id = path_para->d2;
+
+    const char* Rx_pathname = ACM_GetPathName(Rx_path_id);
+    const char* Tx_pathname = ACM_GetPathName(Tx_path_id);
+
+    if ((NULL == Rx_pathname) || (NULL == Tx_pathname))
+    {
+        LOGE( AC_DisablePath, "%s/L%d: RX or TX pathname is NULL.",__FUNCTION__, __LINE__);
+        return;
+    }
+
+    if ((ACM_RC_OK_HIFI_MATCHED != APHAudioPathCheck (Rx_pathname, Tx_pathname))
+            && (ACM_RC_OK_VOICE_MATCHED != APHAudioPathCheck (Rx_pathname, Tx_pathname)))
+    {
+        LOGE( AC_DisablePath, "%s/L%d: RX is not matched with TX.",__FUNCTION__, __LINE__);
+        return;
+    }
+
+    ACMAudioPathDisable(Rx_pathname);
+    ACMAudioPathDisable(Tx_pathname);
+
+    LOGI( AC_DisablePath, "%s/L%d: Rx_path_id =  %d, Rx_pathname =%s,  Tx_path_id =  %d, Tx_pathname = %s",
+            __FUNCTION__, __LINE__, Rx_path_id, Rx_pathname, Tx_path_id, Tx_pathname);
+}
+
+/*
+Function: mute the path which is enabled and unmuted.
+path_para.d1: Rx_path_id
+path_para.d2: Tx_path_id
+path_para.d3: mute
+ */
+void AC_MutePath(AC_IPC_Package_Body *path_para) {
+    int Rx_path_id = path_para->d1;
+    int Tx_path_id = path_para->d2;
+    int mute = path_para->d3;
+
+    const char* Rx_pathname = ACM_GetPathName(Rx_path_id);
+    const char* Tx_pathname = ACM_GetPathName(Tx_path_id);
+
+    if ((NULL == Rx_pathname) || (NULL == Tx_pathname))
+    {
+        LOGE( AC_MutePath, "%s/L%d: RX or TX pathname is NULL.",__FUNCTION__, __LINE__);
+        return;
+    }
+
+    LOGI( AC_MutePath, "%s/L%d: Rx_path_id =  %d, Rx_pathname =%s,  Tx_path_id =  %d, Tx_pathname = %s, mute =%d",
+            __FUNCTION__, __LINE__, Rx_path_id, Rx_pathname, Tx_path_id, Tx_pathname, mute);
+
+    if ((ACM_RC_OK_HIFI_MATCHED != APHAudioPathCheck (Rx_pathname, Tx_pathname))
+            && (ACM_RC_OK_VOICE_MATCHED != APHAudioPathCheck (Rx_pathname, Tx_pathname)))
+    {
+        LOGE( AC_MutePath, "%s/L%d: RX is not matched with TX.",__FUNCTION__, __LINE__);
+        return;
+    }
+
+    ACMAudioPathMute(Rx_pathname, mute);
+    ACMAudioPathMute(Tx_pathname, mute);
+}
+
+/*
+Function:set the volume for enabled path.
+path_para.d1: Rx_path_id
+path_para.d2: Tx_path_id
+path_para.d3: volume
+ */
+void AC_SetPathVolume(AC_IPC_Package_Body *path_para, AC_Digital_Gain *gain) {
+    int Rx_path_id = path_para->d1;
+    int Tx_path_id = path_para->d2;
+    unsigned int Volume = path_para->d3;
+
+    signed char input_gain = 0;
+    signed char input_gain_wb = 0;
+    signed char output_gain = 0;
+    signed char output_gain_wb = 0;
+    signed char rx_sidetone_gain = 0;
+    signed char rx_sidetone_gain_wb = 0;
+    signed char tx_sidetone_gain = 0;
+    signed char tx_sidetone_gain_wb = 0;
+    unsigned char vc_output_vol = Volume;
+    bool use_extra_vol = 0;
+
+    const char* Rx_pathname = ACM_GetPathName(Rx_path_id);
+    const char* Tx_pathname = ACM_GetPathName(Tx_path_id);
+
+    if ((NULL == Rx_pathname) || (NULL == Tx_pathname))
+    {
+        LOGE( AC_SetPathVolume, "%s/L%d: RX or TX pathname is NULL.",__FUNCTION__, __LINE__);
+        return;
+    }
+
+    LOGI( AC_SetPathVolume, "%s/L%d: Rx_path_id =  %d, Rx_pathname =%s,  Tx_path_id =  %d, Tx_pathname = %s, Volume =%d",
+            __FUNCTION__, __LINE__, Rx_path_id, Rx_pathname, Tx_path_id, Tx_pathname, Volume);
+
+    if ((ACM_RC_OK_HIFI_MATCHED != APHAudioPathCheck (Rx_pathname, Tx_pathname))
+            && (ACM_RC_OK_VOICE_MATCHED != APHAudioPathCheck (Rx_pathname, Tx_pathname)))
+    {
+        LOGE( AC_SetPathVolume, "%s/L%d: RX is not matched with TX.",__FUNCTION__, __LINE__);
+        return;
+    }
+
+    ACMAudioPathVolumeSet(Rx_pathname, Volume);
+    ACMAudioPathVolumeSet(Tx_pathname, Volume);
+
+    //get the gain for voice
+    if (ACM_RC_OK_HIFI_MATCHED == APHAudioPathCheck (Rx_pathname, Tx_pathname))
+    {
+        LOGE( AC_SetPathVolume, "%s/L%d: RX is matched with TX about HIFI. Not need to get gain.",__FUNCTION__, __LINE__);
+        return;
+    }
+
+    get_msa_gain_by_path_name(Rx_pathname, Tx_pathname, 100, &input_gain, &input_gain_wb, &tx_sidetone_gain, &tx_sidetone_gain_wb, use_extra_vol);
+    get_msa_gain_by_path_name(Rx_pathname, Rx_pathname, vc_output_vol, &output_gain, &output_gain_wb, &rx_sidetone_gain, &rx_sidetone_gain_wb, use_extra_vol);
+
+    LOGI(AC_SetPathVolume, "%s/L%d: input_gain=0x%x, input_gain_wb=0x%x, output_gain=0x%x, output_gain_wb=0x%x.use_extra_vol=%d.\n",
+            __FUNCTION__, __LINE__, input_gain, input_gain_wb, output_gain, output_gain_wb, use_extra_vol);
+
+    gain->path_direction_Rx = VCM_PATH_OUT;
+    gain->digital_gain_Rx = output_gain | (output_gain_wb << 8);
+    gain->volume_Rx = vc_output_vol;
+
+    gain->path_direction_Tx = VCM_PATH_IN;
+    gain->digital_gain_Tx = input_gain |  (input_gain_wb << 8);
+    gain->volume_Tx = vc_output_vol;
+
+    gain->path_direction_SideTone = VCM_PATH_SIDETONE;
+    gain->digital_gain_SideTone = rx_sidetone_gain |  (rx_sidetone_gain_wb << 8);
+    gain->volume_SideTone = vc_output_vol;
+
+    LOGI(AC_SetPathVolume, "%s/L%d: digital_gain_Rx=0x%x, volume_Rx=%d, digital_gain_Tx=0x%x, volume_Tx=%d, digital_gain_SideTone=%d.\n",
+            __FUNCTION__, __LINE__, gain->digital_gain_Rx, gain->volume_Rx, gain->digital_gain_Tx, gain->volume_Tx, gain->digital_gain_SideTone);
+}
+
+/*
+Function: switch the path from enabled path list to another enabled path list.
+path_para.d1: Rx_path_id
+path_para.d2: Tx_path_id
+path_para.d3: Volume
+ */
+void AC_SwitchPath(AC_IPC_Package_Body *path_para, AC_Digital_Gain *gain) {
+    int Rx_path_id = path_para->d1;
+    int Tx_path_id = path_para->d2;
+    unsigned int Volume = path_para->d3;
+
+    signed char input_gain = 0;
+    signed char input_gain_wb = 0;
+    signed char output_gain = 0;
+    signed char output_gain_wb = 0;
+    signed char rx_sidetone_gain = 0;
+    signed char rx_sidetone_gain_wb = 0;
+    signed char tx_sidetone_gain = 0;
+    signed char tx_sidetone_gain_wb = 0;
+    unsigned char vc_output_vol = Volume;
+    bool use_extra_vol = 0;
+
+    //enable the pointed path
+    const char* Rx_pathname = ACM_GetPathName(Rx_path_id);
+    const char* Tx_pathname = ACM_GetPathName(Tx_path_id);
+
+    if ((NULL == Rx_pathname) || (NULL == Tx_pathname))
+    {
+        LOGE( AC_SwitchPath, "%s/L%d: RX or TX pathname is NULL.",__FUNCTION__, __LINE__);
+        return;
+    }
+
+    if ((ACM_RC_OK_HIFI_MATCHED != APHAudioPathCheck (Rx_pathname, Tx_pathname))
+            && (ACM_RC_OK_VOICE_MATCHED != APHAudioPathCheck (Rx_pathname, Tx_pathname)))
+    {
+        LOGE( AC_SwitchPath, "%s/L%d: RX is not matched with TX.",__FUNCTION__, __LINE__);
+        return;
+    }
+
+    LOGI( AC_SwitchPath, "%s/L%d: Rx_path_id =  %d, Rx_pathname =%s,  Tx_path_id =  %d, Tx_pathname = %s, Volume =%d",
+            __FUNCTION__, __LINE__, Rx_path_id, Rx_pathname, Tx_path_id, Tx_pathname, Volume);
+
+    ACMAudioPathSwitch(Rx_pathname, Tx_pathname, Volume);
+
+    //get the gain for voice
+    if (ACM_RC_OK_HIFI_MATCHED == APHAudioPathCheck (Rx_pathname, Tx_pathname))
+    {
+        LOGE( AC_SwitchPath, "%s/L%d: RX is matched with TX about HIFI. Not need to get gain.",__FUNCTION__, __LINE__);
+        return;
+    }
+
+    get_msa_gain_by_path_name(Rx_pathname, Tx_pathname, 100, &input_gain, &input_gain_wb, &tx_sidetone_gain, &tx_sidetone_gain_wb, use_extra_vol);
+    get_msa_gain_by_path_name(Rx_pathname, Rx_pathname, vc_output_vol, &output_gain, &output_gain_wb, &rx_sidetone_gain, &rx_sidetone_gain_wb, use_extra_vol);
+
+    LOGI(AC_SwitchPath, "%s/L%d: input_gain = %d, input_gain_wb=%d, output_gain = %d, output_gain_wb=%d.use_extra_vol=%d.\n",
+            __FUNCTION__, __LINE__, input_gain, input_gain_wb, output_gain, output_gain_wb, use_extra_vol);
+
+    gain->path_direction_Rx = VCM_PATH_OUT;
+    gain->digital_gain_Rx = output_gain | (output_gain_wb << 8);
+    gain->volume_Rx = vc_output_vol;
+
+    gain->path_direction_Tx = VCM_PATH_IN;
+    gain->digital_gain_Tx = input_gain |  (input_gain_wb << 8);
+    gain->volume_Tx = vc_output_vol;
+
+    gain->path_direction_SideTone = VCM_PATH_SIDETONE;
+    gain->digital_gain_SideTone = rx_sidetone_gain |  (rx_sidetone_gain_wb << 8);
+    gain->volume_SideTone = vc_output_vol;
+
+    LOGI(AC_SwitchPath, "%s/L%d: digital_gain_Rx = %d, volume_Rx=%d, digital_gain_Tx = %d, volume_Tx=%d, digital_gain_SideTone=%d.\n",
+            __FUNCTION__, __LINE__, gain->digital_gain_Rx, gain->volume_Rx, gain->digital_gain_Tx, gain->volume_Tx, gain->digital_gain_SideTone);
+
+}
+
+#ifdef TARGET_mmp_asr1901_KSTR901
+extern void ACM_SendVEtoADSP(void);
+#endif
+
+//server to handle the message from client which is from CATSTUDIO tools ....
+static void ACM_Calibration_Socket_Server_Thread(void *data) {
+    (void)data;
+    unsigned int len;
+    struct sockaddr_un un;
+    AC_IPC_Package rcv_buf;
+
+    prctl(15,"ac_thread");
+    /* create a UNIX domain stream socket */
+    if ((fd_server = socket(AF_UNIX, SOCK_SEQPACKET, 0)) < 0) {
+        LOGE(ACM_Calibration_Socket_Server_Thread, "[Audio Calibration][%s][%d][create socket fail]\n", __FUNCTION__, __LINE__);
+        return;
+    }
+
+    unlink(ACM_CALIBRATION_SOCKET);   /* in case it already exists */
+
+    /* fill in socket address structure */
+    memset(&un, 0, sizeof(un));
+    un.sun_family = AF_UNIX;
+    strcpy(un.sun_path, ACM_CALIBRATION_SOCKET);
+    len = offsetof(struct sockaddr_un, sun_path) + strlen(ACM_CALIBRATION_SOCKET);
+
+    LOGI(ACM_Calibration_Socket_Server_Thread, "%s/L%d: addr=%s.\n", __FUNCTION__, __LINE__, un.sun_path);
+
+    /* bind the name to the descriptor */
+    if (bind(fd_server, (struct sockaddr *)&un, len) < 0) {
+
+        LOGE(ACM_Calibration_Socket_Server_Thread, "[Audio Calibration][%s][%d][bind fail][error %d (%s)]\n" \
+                , __FUNCTION__, __LINE__,errno, strerror(errno));
+        close(fd_server);
+        return;
+    }
+
+    if (chmod(ACM_CALIBRATION_SOCKET, 0666) < 0) {
+        LOGE(ACM_Calibration_Socket_Server_Thread, "[Audio Calibration][%s][%d]FAIL to chmod ACM_CALIBRATION_SOCKET to 0666\n", __FUNCTION__, __LINE__);
+        close(fd_server);
+        return;
+    }
+    if (listen(fd_server, QLEN) < 0) { /* tell kernel we're a server */
+        LOGE(ACM_Calibration_Socket_Server_Thread, "[Audio Calibration][%s][%d][listen fail]\n", __FUNCTION__, __LINE__);
+        close(fd_server);
+        return;
+    }
+
+    while(1) {
+        len = sizeof(un);
+        //close last connection
+        if (clientfd_server >= 0) {
+            close(clientfd_server);
+            clientfd_server = -1;
+            //usleep(10000);
+        }
+
+        if ((clientfd_server = accept(fd_server, (struct sockaddr *)&un, &len)) < 0) {
+            LOGE(ACM_Calibration_Socket_Server_Thread, "%s/L%d: Audio Calibration accept fail\n", __FUNCTION__, __LINE__);
+            continue;
+        }
+
+        if(read(clientfd_server, &rcv_buf, sizeof(rcv_buf))==-1) {
+            LOGE(ACM_Calibration_Socket_Server_Thread, "%s/L%d: read fail\n", __FUNCTION__, __LINE__);
+            continue;
+        }
+
+        LOGI(ACM_Calibration_Socket_Server_Thread, "%s/L%d: [receive type:0x%lx]-[d1:0x%lx][d2:0x%lx][d3:0x%lx][d4:0x%lx]\n",
+                __FUNCTION__, __LINE__,
+                rcv_buf.type, rcv_buf.body.d1, rcv_buf.body.d2, rcv_buf.body.d3, rcv_buf.body.d4);
+
+        switch (rcv_buf.type) {
+            case AUDIO_PHY_GetPathList:
+                {
+                    PathsList paths_list;
+                    int i = 0;
+                    const ACMAPH_AudioPathID *path_config_table = NULL;
+
+                    memset(&paths_list, 0x00, sizeof(paths_list));
+                    path_config_table = ACM_GetPathConfigTable();
+
+                    while (i < APH_PATH_ID_CNT)
+                    {
+                        strcpy(paths_list.path[paths_list.num++], (const char *)path_config_table[i].PathName);
+                        i++;
+                    }
+
+                    if(write(clientfd_server, &paths_list, sizeof(paths_list)) == -1)
+                    {
+                        LOGE(ACM_Calibration_Socket_Server_Thread, "%s/L%d: Get paths list failed", __FUNCTION__, __LINE__);
+                        continue;
+                    }
+
+                    for(i = 0; i < paths_list.num; i++)
+                    {
+                        LOGI(ACM_Calibration_Socket_Server_Thread, "  : %s\n", paths_list.path[i]);
+                    }
+
+                    break;
+                }
+
+            case AUDIO_PHY_GetPathStatus:
+                {
+                    char tmp_buffer[PATHSTATUS_MAX] = {0};
+
+                    if (ACMGetPathStatus(tmp_buffer, PATHSTATUS_MAX) != ACM_RC_OK)
+                    {
+                        sprintf(tmp_buffer, "-> Fail to get status!\n");
+                        LOGE(ACM_Calibration_Socket_Server_Thread, "%s/L%d: Get paths status failed", __FUNCTION__, __LINE__);
+                        continue;
+                    }
+
+                    LOGI(ACM_Calibration_Socket_Server_Thread, "%s.......", tmp_buffer);
+
+                    if(write(clientfd_server, tmp_buffer, PATHSTATUS_MAX*sizeof(char)) == -1)
+                    {
+                        LOGE(ACM_Calibration_Socket_Server_Thread, "%s/L%d: Get paths status failed", __FUNCTION__, __LINE__);
+                        continue;
+                    }
+
+                    break;
+                }
+
+            case AUDIO_PHY_GetAudioMode:
+                {
+                    audio_mode_t mode = AUDIO_MODE_INVALID;
+                    int pcm_role = 0;
+                    int pcm_rate = 0;
+
+                    get_pcm_config(&pcm_role, &pcm_rate);
+                    LOGI(ACM_Calibration_Socket_Server_Thread, "%s: modem_is_master=%s, modem_is_wb=%s.......", __FUNCTION__, pcm_role?"TRUE":"FALSE", pcm_rate?"WB":"NB");
+
+                    mode = ACMGetAudioMode();
+
+                    if ((mode != AUDIO_MODE_NORMAL)  && (mode != AUDIO_MODE_IN_CALL))
+                    {
+                        LOGE(ACM_Calibration_Socket_Server_Thread, "mode is not AUDIO_MODE_NORMAL and AUDIO_MODE_IN_CALL");
+                        continue;
+                    }
+
+                    LOGI(ACM_Calibration_Socket_Server_Thread, "mode = %s.......",
+                            (mode == AUDIO_MODE_NORMAL) ? "AUDIO_MODE_NORMAL" : "AUDIO_MODE_IN_CALL");
+
+                    if(write(clientfd_server, &mode, sizeof(audio_mode_t)) == -1)
+                    {
+                        LOGE(ACM_Calibration_Socket_Server_Thread, "%s/L%d: Get mode failed", __FUNCTION__, __LINE__);
+                        continue;
+                    }
+
+                    break;
+                }
+            case AUDIO_PHY_ReloadCalibrationData:
+                {
+                    AC_Digital_Gain gain;
+
+                    LOGI(ACM_Calibration_Socket_Server_Thread, "%s/L%d: ReloadCalibrationData", __FUNCTION__, __LINE__);
+                    memset(&gain, 0x00, sizeof(AC_Digital_Gain));
+
+                    AC_ReloadCalibrationData(&gain);
+
+                    if(write(clientfd_server, &gain, sizeof(AC_Digital_Gain)) == -1) {
+                        LOGE(ACM_Calibration_Socket_Server_Thread, "%s/L%d: Audio Calibration failed", __FUNCTION__, __LINE__);
+                        continue;
+                    }
+                }
+
+                LOGI(ACM_Calibration_Socket_Server_Thread, "%s/L%d: ReloadCalibrationData", __FUNCTION__, __LINE__);
+                break;
+
+            case AUDIO_PHY_SetPathVolume:
+                {
+                    AC_Digital_Gain gain;
+
+                    LOGI(ACM_Calibration_Socket_Server_Thread, "%s/L%d: SetPathVolume", __FUNCTION__, __LINE__);
+                    memset(&gain, 0x00, sizeof(AC_Digital_Gain));
+                    AC_SetPathVolume(&rcv_buf.body, &gain);
+
+                    if(write(clientfd_server, &gain, sizeof(AC_Digital_Gain)) == -1) {
+                        LOGE(ACM_Calibration_Socket_Server_Thread, "%s/L%d: Audio Calibration  failed", __FUNCTION__, __LINE__);
+                        continue;
+                    }
+                }
+                LOGI(ACM_Calibration_Socket_Server_Thread, "%s/L%d: SetPathVolume", __FUNCTION__, __LINE__);
+                break;
+
+            case AUDIO_PHY_EnablePath:
+                {
+                    AC_Digital_Gain gain;
+
+                    LOGI(ACM_Calibration_Socket_Server_Thread, "%s/L%d: EnablePath", __FUNCTION__, __LINE__);
+                    memset(&gain, 0x00, sizeof(AC_Digital_Gain));
+                    AC_EnablePath(&rcv_buf.body, &gain);
+
+                    if(write(clientfd_server, &gain, sizeof(AC_Digital_Gain)) == -1) {
+                        LOGE(ACM_Calibration_Socket_Server_Thread, "%s/L%d: Audio Calibration  failed", __FUNCTION__, __LINE__);
+                        continue;
+                    }
+                }
+
+                LOGI(ACM_Calibration_Socket_Server_Thread, "%s/L%d: EnablePath", __FUNCTION__, __LINE__);
+                break;
+
+            case AUDIO_PHY_DisablePath:
+                LOGI(ACM_Calibration_Socket_Server_Thread, "%s/L%d: DisablePath", __FUNCTION__, __LINE__);
+                AC_DisablePath(&rcv_buf.body);
+                break;
+
+            case AUDIO_PHY_MutePath:
+                LOGI(ACM_Calibration_Socket_Server_Thread, "%s/L%d: MutePath", __FUNCTION__, __LINE__);
+                AC_MutePath(&rcv_buf.body);
+                break;
+
+            case AUDIO_PHY_SwitchPath:
+                {
+                    AC_Digital_Gain gain;
+
+                    memset(&gain, 0x00, sizeof(AC_Digital_Gain));
+                    LOGI(ACM_Calibration_Socket_Server_Thread, "%s/L%d: SwitchPath", __FUNCTION__, __LINE__);
+                    AC_SwitchPath(&rcv_buf.body, &gain);
+
+                    if(write(clientfd_server, &gain, sizeof(AC_Digital_Gain)) == -1) {
+                        LOGE(ACM_Calibration_Socket_Server_Thread, "%s/L%d: Audio Calibration  failed", __FUNCTION__, __LINE__);
+                        continue;
+                    }
+                }
+
+                LOGI(ACM_Calibration_Socket_Server_Thread, "%s/L%d: SwitchPath", __FUNCTION__, __LINE__);
+                break;
+
+#ifdef TARGET_mmp_asr1901_KSTR901
+            case AUDIO_PHY_SendVEtoADSP:
+                LOGI(ACM_Calibration_Socket_Server_Thread, "%s/L%d: SendVEtoADSP", __FUNCTION__, __LINE__);
+                ACM_SendVEtoADSP();
+                break;
+#endif
+
+            default:
+                continue;
+        }
+    }
+
+    unlink(ACM_CALIBRATION_SOCKET);
+    return;
+}
+
+
+void ACM_Init_Calibration_IPC(void)
+{
+    pthread_create( &ACM_Calibration_Server, NULL, (void *)ACM_Calibration_Socket_Server_Thread, NULL);
+}
+
+void ACM_Cancel_Calibration_IPC(void)
+{
+    pthread_cancel(ACM_Calibration_Server);
+
+    if (pthread_join(ACM_Calibration_Server, NULL)) {
+        LOGE(ACM_Cancel_Calibration_IPC, "%s/L%d: fail to pthread_join() ACM_Calibration_Server", __FUNCTION__, __LINE__);
+    }
+
+    if (fd_server >= 0) {
+        close(fd_server);
+        fd_server = -1;
+        LOGE(ACM_Cancel_Calibration_IPC, "%s/L%d: close fd_server.", __FUNCTION__, __LINE__);
+    }
+
+    if (clientfd_server >= 0) {
+        close(clientfd_server);
+        clientfd_server = -1;
+        LOGE(ACM_Cancel_Calibration_IPC, "%s/L%d: close clientfd_server.", __FUNCTION__, __LINE__);
+    }
+
+    return;
+}
diff --git a/marvell/services/audio/libacm/acm/src/acm_alc5616.h b/marvell/services/audio/libacm/acm/src/acm_alc5616.h
new file mode 100644
index 0000000..65d9ad7
--- /dev/null
+++ b/marvell/services/audio/libacm/acm/src/acm_alc5616.h
@@ -0,0 +1,275 @@
+/*
+ * ASR Audio path definition of ALC5616 
+ *
+ * Copyright (C) 2018 ASR Microelectronic Ltd.
+ *
+ * Author: Chen wen<wenchen@asrmicro.com>
+ *
+ * This file contains proprietary information.
+ * No dissemination allowed without prior written permission from
+ * ASR Microelectronic Ltd.
+ *
+ * File Description:
+ *
+ * This file contains header for audio path definition of ALC5616 
+ */
+
+#ifndef ACM_ALC5616_H
+#define ACM_ALC5616_H
+
+#define CODEC_ALC5616_VOICE_REG70         0x70
+#define CODEC_ALC5616_VOICE_MASTER        0x0082   //bit15=0 master
+#define CODEC_ALC5616_VOICE_SLAVE         0x8082   //bit15=1 slave
+
+//////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////
+/////////////////////////APH_PATH_ID_HIFIPLAYTOEARPHONE//////////////////////////
+ACMAPH_Register ACM_HiFiPlayToEarphone_Disable[]={
+    {ALC5616, 0x70, 0x8000},                        {ALC5616, 0x63, 0x00C6},{ALC5616, 0x3D, 0x2000},{ALC5616, 0x61, 0x8000},
+    {ALC5616, 0x62, 0x0000},{ALC5616, 0x65, 0x0000},{ALC5616, 0x66, 0x0000},{ALC5616, 0x8E, 0x0000},{ALC5616, 0x8F, 0x1100},
+    {ALC5616, 0x2A, 0x5252},{ALC5616, 0x4F, 0x0279},{ALC5616, 0x52, 0x0279},{ALC5616, 0x53, 0xF000},{ALC5616, 0x03, 0xC8C8},
+    {ALC5616, 0x05, 0x0000}
+};
+ACMAPH_Register ACM_HiFiPlayToEarphone_Enable[]={
+    {ALC5616, 0x70, CODEC_ALC5616_VOICE_SLAVE},     {ALC5616, 0x63, 0xF8DE},{ALC5616, 0x3D, 0x3600},{ALC5616, 0x61, 0x9804},
+    {ALC5616, 0x62, 0x8800},{ALC5616, 0x65, 0xC800},{ALC5616, 0x66, 0x3000},{ALC5616, 0x8E, 0x0008},{ALC5616, 0x8F, 0x3100},
+    {ALC5616, 0x2A, 0x1250},{ALC5616, 0x4F, 0x0278},{ALC5616, 0x52, 0x0278},{ALC5616, 0x53, 0xC000},{ALC5616, 0x03, 0x0808},
+    {ALC5616, 0x05, 0x8000}
+};
+
+/////////////////////////APH_PATH_ID_HIFIPLAYTOSPKR//////////////////////////
+ACMAPH_Register ACM_HiFiPlayToSPKR_Disable[]={
+    {ALC5616, 0x70, 0x8000},                        {ALC5616, 0x63, 0x00C6},{ALC5616, 0x3D, 0x2000},{ALC5616, 0x61, 0x8000},
+    {ALC5616, 0x62, 0x0000},{ALC5616, 0x65, 0x0000},{ALC5616, 0x66, 0x0000},{ALC5616, 0x8E, 0x0000},{ALC5616, 0x8F, 0x1100},
+    {ALC5616, 0x2A, 0x5252},{ALC5616, 0x4F, 0x0279},{ALC5616, 0x52, 0x0279},{ALC5616, 0x53, 0xF000},{ALC5616, 0x03, 0xC8C8},
+    {ALC5616, 0x05, 0x0000}
+};
+ACMAPH_Register ACM_HiFiPlayToSPKR_Enable[]={
+    {ALC5616, 0x70, CODEC_ALC5616_VOICE_SLAVE},     {ALC5616, 0x63, 0xF8DE},{ALC5616, 0x3D, 0x3600},{ALC5616, 0x61, 0x9804},
+    {ALC5616, 0x62, 0x8800},{ALC5616, 0x65, 0xC800},{ALC5616, 0x66, 0x3000},{ALC5616, 0x8E, 0x0008},{ALC5616, 0x8F, 0x3100},
+    {ALC5616, 0x2A, 0x1250},{ALC5616, 0x4F, 0x0278},{ALC5616, 0x52, 0x0278},{ALC5616, 0x53, 0xC000},{ALC5616, 0x03, 0x0808},
+    {ALC5616, 0x05, 0x8000}
+};
+
+/////////////////////////APH_PATH_ID_HIFIPLAYTOHP//////////////////////////
+ACMAPH_Register ACM_HiFiPlayToHP_Disable[]={
+    {ALC5616, 0x70, 0x8000},                        {ALC5616, 0x63, 0x00C6},{ALC5616, 0x3D, 0x2000},{ALC5616, 0x61, 0x8000},
+    {ALC5616, 0x62, 0x0000},{ALC5616, 0x65, 0x0000},{ALC5616, 0x66, 0x0000},{ALC5616, 0x8E, 0x0000},{ALC5616, 0x8F, 0x1100},
+    {ALC5616, 0x2A, 0x5252},{ALC5616, 0x4F, 0x0279},{ALC5616, 0x52, 0x0279},{ALC5616, 0x45, 0x7000},{ALC5616, 0x02, 0xC8C8},
+    {ALC5616, 0x1E, 0x0000},{ALC5616, 0xD3, 0xB320}
+};
+ACMAPH_Register ACM_HiFiPlayToHP_Enable[]={
+    {ALC5616, 0x70, CODEC_ALC5616_VOICE_SLAVE},     {ALC5616, 0x63, 0xE8DE},{ALC5616, 0x3D, 0x3600},{ALC5616, 0x61, 0x9804},
+    {ALC5616, 0x62, 0x8800},{ALC5616, 0x65, 0xCC00},{ALC5616, 0x66, 0x0C00},{ALC5616, 0x8E, 0x001D},{ALC5616, 0x8F, 0x3100},
+    {ALC5616, 0x2A, 0x1250},{ALC5616, 0x4F, 0x0278},{ALC5616, 0x52, 0x0278},{ALC5616, 0x45, 0x5000},{ALC5616, 0x02, 0x0808},
+    {ALC5616, 0x1E, 0x8000},{ALC5616, 0xD3, 0x2A00}
+};
+
+/////////////////////////APH_PATH_ID_HIFIRECORDFROMMIC1//////////////////////////
+ACMAPH_Register ACM_HiFiRecordFromMic1_Disable[]={
+    {ALC5616, 0x70, 0x8000},                        {ALC5616, 0x63, 0x00C6},{ALC5616, 0x3D, 0x2000},{ALC5616, 0x61, 0x8000},
+    {ALC5616, 0x62, 0x0000},{ALC5616, 0x65, 0x0000},{ALC5616, 0x0D, 0x0000},{ALC5616, 0x3C, 0x006F},{ALC5616, 0x3E, 0x006F},
+    {ALC5616, 0x27, 0x7860},
+#if defined(TARGET_mmp_asr1901_KSTR901) && defined(CODEC_PCM_48KHz)
+    {ALC5616, 0x64, 0x0204}
+#else
+    {ALC5616, 0x64, 0x0004}
+#endif
+};
+ACMAPH_Register ACM_HiFiRecordFromMic1_Enable[]={
+    {ALC5616, 0x70, CODEC_ALC5616_VOICE_SLAVE},     {ALC5616, 0x63, 0xF8DE},{ALC5616, 0x3D, 0x3600},{ALC5616, 0x61, 0x9804},
+    {ALC5616, 0x62, 0x8800},{ALC5616, 0x65, 0xC800},{ALC5616, 0x0D, 0x0540},{ALC5616, 0x3C, 0x006B},{ALC5616, 0x3E, 0x006B},
+    {ALC5616, 0x27, 0x3860},
+#if defined(TARGET_mmp_asr1901_KSTR901) && defined(CODEC_PCM_48KHz)
+    {ALC5616, 0x64, 0x4A04}
+#else
+    {ALC5616, 0x64, 0x4804}
+#endif
+};
+ACMAPH_Register ACM_HiFiRecordFromMic1_Mute[]={
+    {ALC5616, 0x1C, 0xAFAF},
+};
+ACMAPH_Register ACM_HiFiRecordFromMic1_UnMute[]={
+    {ALC5616, 0x1C, 0x4141},
+};
+/////////////////////////APH_PATH_ID_HIFIRECORDFROMHSMIC//////////////////////////
+ACMAPH_Register ACM_HiFiRecordFromHsMic_Disable[]={
+    {ALC5616, 0x70, 0x8000},                        {ALC5616, 0x63, 0x00C6},{ALC5616, 0x3D, 0x2000},{ALC5616, 0x61, 0x8000},
+    {ALC5616, 0x62, 0x0000},{ALC5616, 0x65, 0x0000},{ALC5616, 0x0D, 0x0540},{ALC5616, 0x3C, 0x006F},{ALC5616, 0x3E, 0x006F},
+    {ALC5616, 0x27, 0x7860},
+#if defined(TARGET_mmp_asr1901_KSTR901) && defined(CODEC_PCM_48KHz)
+    {ALC5616, 0x64, 0x0204}
+#else
+    {ALC5616, 0x64, 0x0004}
+#endif
+};
+ACMAPH_Register ACM_HiFiRecordFromHsMic_Enable[]={
+    {ALC5616, 0x70, CODEC_ALC5616_VOICE_SLAVE},     {ALC5616, 0x63, 0xE8DE},{ALC5616, 0x3D, 0x3600},{ALC5616, 0x61, 0x9804},
+    {ALC5616, 0x62, 0x8800},{ALC5616, 0x65, 0xCC00},{ALC5616, 0x0D, 0x0000},{ALC5616, 0x3C, 0x006D},{ALC5616, 0x3E, 0x006D},
+    {ALC5616, 0x27, 0x3820},
+#if defined(TARGET_mmp_asr1901_KSTR901) && defined(CODEC_PCM_48KHz)
+    {ALC5616, 0x64, 0x8A24}
+#else
+    {ALC5616, 0x64, 0x8824}
+#endif
+};
+ACMAPH_Register ACM_HiFiRecordFromHsMic_Mute[]={
+    {ALC5616, 0x1C, 0xAFAF},
+};
+ACMAPH_Register ACM_HiFiRecordFromHsMic_UnMute[]={
+    {ALC5616, 0x1C, 0x4141},
+};
+//////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////
+/////////////////////////APH_PATH_ID_VOICEPLAYTOEARPHONE//////////////////////////
+
+ACMAPH_Register ACM_VoicePlayToEarphone_Disable[]={
+    {ALC5616, 0x70, 0x8000},                        {ALC5616, 0x63, 0x00C6},{ALC5616, 0x3D, 0x2000},{ALC5616, 0x61, 0x8000},
+    {ALC5616, 0x62, 0x0000},{ALC5616, 0x65, 0x0000},{ALC5616, 0x66, 0x0000},{ALC5616, 0x8E, 0x0000},{ALC5616, 0x8F, 0x1100},
+    {ALC5616, 0x2A, 0x5252},{ALC5616, 0x4F, 0x0279},{ALC5616, 0x52, 0x0279},{ALC5616, 0x53, 0xF000},{ALC5616, 0x03, 0xC8C8},
+    {ALC5616, 0x05, 0x0000}
+};
+ACMAPH_Register ACM_VoicePlayToEarphone_Enable[]={
+    {ALC5616, 0x70, CODEC_ALC5616_VOICE_SLAVE},     {ALC5616, 0x63, 0xF8DE},{ALC5616, 0x3D, 0x3600},{ALC5616, 0x61, 0x9804},
+    {ALC5616, 0x62, 0x8800},{ALC5616, 0x65, 0xC800},{ALC5616, 0x66, 0x3000},{ALC5616, 0x8E, 0x0008},{ALC5616, 0x8F, 0x3100},
+    {ALC5616, 0x2A, 0x1250},{ALC5616, 0x4F, 0x0278},{ALC5616, 0x52, 0x0278},{ALC5616, 0x53, 0xC000},{ALC5616, 0x03, 0x0808},
+    {ALC5616, 0x05, 0x8000}
+};
+
+/////////////////////////APH_PATH_ID_VOICEPLAYTOSPKR//////////////////////////
+ACMAPH_Register ACM_VoicePlayToSPKR_Disable[]={
+    {ALC5616, 0x70, 0x8000},                        {ALC5616, 0x63, 0x00C6},{ALC5616, 0x3D, 0x2000},{ALC5616, 0x61, 0x8000},
+    {ALC5616, 0x62, 0x0000},{ALC5616, 0x65, 0x0000},{ALC5616, 0x66, 0x0000},{ALC5616, 0x8E, 0x0000},{ALC5616, 0x8F, 0x1100},
+    {ALC5616, 0x2A, 0x5252},{ALC5616, 0x4F, 0x0279},{ALC5616, 0x52, 0x0279},{ALC5616, 0x53, 0xF000},{ALC5616, 0x03, 0xC8C8},
+    {ALC5616, 0x05, 0x0000}
+};
+ACMAPH_Register ACM_VoicePlayToSPKR_Enable[]={
+    {ALC5616, 0x70, CODEC_ALC5616_VOICE_SLAVE},     {ALC5616, 0x63, 0xF8DE},{ALC5616, 0x3D, 0x3600},{ALC5616, 0x61, 0x9804},
+    {ALC5616, 0x62, 0x8800},{ALC5616, 0x65, 0xC800},{ALC5616, 0x66, 0x3000},{ALC5616, 0x8E, 0x0008},{ALC5616, 0x8F, 0x3100},
+    {ALC5616, 0x2A, 0x1250},{ALC5616, 0x4F, 0x0278},{ALC5616, 0x52, 0x0278},{ALC5616, 0x53, 0xC000},{ALC5616, 0x03, 0x0808},
+    {ALC5616, 0x05, 0x8000}
+};
+
+/////////////////////////APH_PATH_ID_VOICEPLAYTOHP//////////////////////////
+ACMAPH_Register ACM_VoicePlayToHP_Disable[]={
+    {ALC5616, 0x70, 0x8000},                        {ALC5616, 0x63, 0x00C6},{ALC5616, 0x3D, 0x2000},{ALC5616, 0x61, 0x8000},
+    {ALC5616, 0x62, 0x0000},{ALC5616, 0x65, 0x0000},{ALC5616, 0x66, 0x0000},{ALC5616, 0x8E, 0x0000},{ALC5616, 0x8F, 0x1100},
+    {ALC5616, 0x2A, 0x5252},{ALC5616, 0x4F, 0x0279},{ALC5616, 0x52, 0x0279},{ALC5616, 0x45, 0x7000},{ALC5616, 0x02, 0xC8C8},
+    {ALC5616, 0x1E, 0x0000},{ALC5616, 0xD3, 0xB320}
+};
+ACMAPH_Register ACM_VoicePlayToHP_Enable[]={
+    {ALC5616, 0x70, CODEC_ALC5616_VOICE_SLAVE},     {ALC5616, 0x63, 0xE8DE},{ALC5616, 0x3D, 0x3600},{ALC5616, 0x61, 0x9804},
+    {ALC5616, 0x62, 0x8800},{ALC5616, 0x65, 0xCC00},{ALC5616, 0x66, 0x0C00},{ALC5616, 0x8E, 0x001D},{ALC5616, 0x8F, 0x3100},
+    {ALC5616, 0x2A, 0x1250},{ALC5616, 0x4F, 0x0278},{ALC5616, 0x52, 0x0278},{ALC5616, 0x45, 0x5000},{ALC5616, 0x02, 0x0808},
+    {ALC5616, 0x1E, 0x8000},{ALC5616, 0xD3, 0x2A00}
+};
+
+/////////////////////////APH_PATH_ID_VOICERECORDFROMMIC1//////////////////////////
+ACMAPH_Register ACM_VoiceRecordFromMic1_Disable[]={
+    {ALC5616, 0x70, 0x8000},                        {ALC5616, 0x63, 0x00C6},{ALC5616, 0x3D, 0x2000},{ALC5616, 0x61, 0x8000},
+    {ALC5616, 0x62, 0x0000},{ALC5616, 0x65, 0x0000},{ALC5616, 0x0D, 0x0000},{ALC5616, 0x3C, 0x006F},{ALC5616, 0x3E, 0x006F},
+    {ALC5616, 0x27, 0x7860},
+#if defined(TARGET_mmp_asr1901_KSTR901) && defined(CODEC_PCM_48KHz)
+    {ALC5616, 0x64, 0x0204}
+#else
+    {ALC5616, 0x64, 0x0004}
+#endif
+};
+ACMAPH_Register ACM_VoiceRecordFromMic1_Enable[]={
+    {ALC5616, 0x70, CODEC_ALC5616_VOICE_SLAVE},     {ALC5616, 0x63, 0xF8DE},{ALC5616, 0x3D, 0x3600},{ALC5616, 0x61, 0x9804},
+    {ALC5616, 0x62, 0x8800},{ALC5616, 0x65, 0xC800},{ALC5616, 0x0D, 0x0540},{ALC5616, 0x3C, 0x006B},{ALC5616, 0x3E, 0x006B},
+    {ALC5616, 0x27, 0x3860},
+#if defined(TARGET_mmp_asr1901_KSTR901) && defined(CODEC_PCM_48KHz)
+    {ALC5616, 0x64, 0x4A04}
+#else
+    {ALC5616, 0x64, 0x4804}
+#endif
+};
+ACMAPH_Register ACM_VoiceRecordFromMic1_Mute[]={
+    {ALC5616, 0x1C, 0xAFAF},
+};
+ACMAPH_Register ACM_VoiceRecordFromMic1_UnMute[]={
+    {ALC5616, 0x1C, 0x4141},
+};
+/////////////////////////APH_PATH_ID_VOICERECORDFROMHSMIC//////////////////////////
+ACMAPH_Register ACM_VoiceRecordFromHsMic_Disable[]={
+    {ALC5616, 0x70, 0x8000},                        {ALC5616, 0x63, 0x00C6},{ALC5616, 0x3D, 0x2000},{ALC5616, 0x61, 0x8000},
+    {ALC5616, 0x62, 0x0000},{ALC5616, 0x65, 0x0000},{ALC5616, 0x0D, 0x0540},{ALC5616, 0x3C, 0x006F},{ALC5616, 0x3E, 0x006F},
+    {ALC5616, 0x27, 0x7860},
+#if defined(TARGET_mmp_asr1901_KSTR901) && defined(CODEC_PCM_48KHz)
+    {ALC5616, 0x64, 0x0204}
+#else
+    {ALC5616, 0x64, 0x0004}
+#endif
+};
+ACMAPH_Register ACM_VoiceRecordFromHsMic_Enable[]={
+    {ALC5616, 0x70, CODEC_ALC5616_VOICE_SLAVE},     {ALC5616, 0x63, 0xE8DE},{ALC5616, 0x3D, 0x3600},{ALC5616, 0x61, 0x9804},
+    {ALC5616, 0x62, 0x8800},{ALC5616, 0x65, 0xCC00},{ALC5616, 0x0D, 0x0000},{ALC5616, 0x3C, 0x006D},{ALC5616, 0x3E, 0x006D},
+    {ALC5616, 0x27, 0x3820},
+#if defined(TARGET_mmp_asr1901_KSTR901) && defined(CODEC_PCM_48KHz)
+    {ALC5616, 0x64, 0x8A24}
+#else
+    {ALC5616, 0x64, 0x8824}
+#endif
+};
+ACMAPH_Register ACM_VoiceRecordFromHsMic_Mute[]={
+    {ALC5616, 0x1C, 0xAFAF},
+};
+ACMAPH_Register ACM_VoiceRecordFromHsMic_UnMute[]={
+    {ALC5616, 0x1C, 0x4141},
+};
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+static ACMAPH_Component ACM_Disable[APH_PATH_ID_CNT]={
+    {APH_PATH_ID_HIFIPLAYTOEARPHONE,    ACM_HiFiPlayToEarphone_Disable,     sizeof(ACM_HiFiPlayToEarphone_Disable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIPLAYTOSPKR,        ACM_HiFiPlayToSPKR_Disable,         sizeof(ACM_HiFiPlayToSPKR_Disable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIPLAYTOHP,          ACM_HiFiPlayToHP_Disable,           sizeof(ACM_HiFiPlayToHP_Disable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIRECORDFROMMIC1,    ACM_HiFiRecordFromMic1_Disable,     sizeof(ACM_HiFiRecordFromMic1_Disable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIRECORDFROMHSMIC,   ACM_HiFiRecordFromHsMic_Disable,    sizeof(ACM_HiFiRecordFromHsMic_Disable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICEPLAYTOEARPHONE,   ACM_VoicePlayToEarphone_Disable,    sizeof(ACM_VoicePlayToEarphone_Disable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICEPLAYTOSPKR,       ACM_VoicePlayToSPKR_Disable,        sizeof(ACM_VoicePlayToSPKR_Disable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICEPLAYTOHP,         ACM_VoicePlayToHP_Disable,          sizeof(ACM_VoicePlayToHP_Disable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICERECORDFROMMIC1,   ACM_VoiceRecordFromMic1_Disable,    sizeof(ACM_VoiceRecordFromMic1_Disable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICERECORDFROMHSMIC,  ACM_VoiceRecordFromHsMic_Disable,   sizeof(ACM_VoiceRecordFromHsMic_Disable)/sizeof(ACMAPH_Register)},
+};
+
+static ACMAPH_Component ACM_Enable[APH_PATH_ID_CNT]={
+    {APH_PATH_ID_HIFIPLAYTOEARPHONE,    ACM_HiFiPlayToEarphone_Enable,      sizeof(ACM_HiFiPlayToEarphone_Enable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIPLAYTOSPKR,        ACM_HiFiPlayToSPKR_Enable,          sizeof(ACM_HiFiPlayToSPKR_Enable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIPLAYTOHP,          ACM_HiFiPlayToHP_Enable,            sizeof(ACM_HiFiPlayToHP_Enable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIRECORDFROMMIC1,    ACM_HiFiRecordFromMic1_Enable,      sizeof(ACM_HiFiRecordFromMic1_Enable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIRECORDFROMHSMIC,   ACM_HiFiRecordFromHsMic_Enable,     sizeof(ACM_HiFiRecordFromHsMic_Enable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICEPLAYTOEARPHONE,   ACM_VoicePlayToEarphone_Enable,     sizeof(ACM_VoicePlayToEarphone_Enable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICEPLAYTOSPKR,       ACM_VoicePlayToSPKR_Enable,         sizeof(ACM_VoicePlayToSPKR_Enable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICEPLAYTOHP,         ACM_VoicePlayToHP_Enable,           sizeof(ACM_VoicePlayToHP_Enable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICERECORDFROMMIC1,   ACM_VoiceRecordFromMic1_Enable,     sizeof(ACM_VoiceRecordFromMic1_Enable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICERECORDFROMHSMIC,  ACM_VoiceRecordFromHsMic_Enable,    sizeof(ACM_VoiceRecordFromHsMic_Enable)/sizeof(ACMAPH_Register)},
+};
+
+static ACMAPH_Component ACM_Mute[APH_PATH_IN_CNT]={
+    {APH_PATH_ID_HIFIRECORDFROMMIC1,    ACM_HiFiRecordFromMic1_Mute,      sizeof(ACM_HiFiRecordFromMic1_Mute)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIRECORDFROMHSMIC,   ACM_HiFiRecordFromHsMic_Mute,     sizeof(ACM_HiFiRecordFromHsMic_Mute)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICERECORDFROMMIC1,   ACM_VoiceRecordFromMic1_Mute,     sizeof(ACM_VoiceRecordFromMic1_Mute)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICERECORDFROMHSMIC,  ACM_VoiceRecordFromHsMic_Mute,    sizeof(ACM_VoiceRecordFromHsMic_Mute)/sizeof(ACMAPH_Register)},
+};
+static ACMAPH_Component ACM_UnMute[APH_PATH_IN_CNT]={
+    {APH_PATH_ID_HIFIRECORDFROMMIC1,    ACM_HiFiRecordFromMic1_UnMute,      sizeof(ACM_HiFiRecordFromMic1_UnMute)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIRECORDFROMHSMIC,   ACM_HiFiRecordFromHsMic_UnMute,     sizeof(ACM_HiFiRecordFromHsMic_UnMute)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICERECORDFROMMIC1,   ACM_VoiceRecordFromMic1_UnMute,     sizeof(ACM_VoiceRecordFromMic1_UnMute)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICERECORDFROMHSMIC,  ACM_VoiceRecordFromHsMic_UnMute,    sizeof(ACM_VoiceRecordFromHsMic_UnMute)/sizeof(ACMAPH_Register)},
+};
+
+extern ACH_ComponentHandler ALC5616_handler;
+
+static APH_ACHComponent ACH_component_table[] = {
+    {ALC5616, &ALC5616_handler},
+};
+//Sorted as APH_AudioComponent
+static char APH_AudioComponent_Name[][16]= {
+    "ELBA",
+    "USTICA",
+    "DELAY",
+    "NAU8810",
+    "ALC5616"
+} ;
+#endif
diff --git a/marvell/services/audio/libacm/acm/src/acm_alc5616_handle.c b/marvell/services/audio/libacm/acm/src/acm_alc5616_handle.c
new file mode 100644
index 0000000..a53dd97
--- /dev/null
+++ b/marvell/services/audio/libacm/acm/src/acm_alc5616_handle.c
@@ -0,0 +1,229 @@
+/*
+ * 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_ach_alc5616"
+#define LOG_NDEBUG 0
+
+#include <cutils/log.h>
+#include "acm_alc5616_handle.h"
+
+int codec_reg_num = NUM_OF_REGS;
+
+static void ALC5616_Enable(void);
+static void ALC5616_Disable(void);
+static void ALC5616_Reset(void);
+static void ALC5616_GetTypeAndID(int *type, unsigned char *id);
+static ACH_ReturnCode ALC5616_Handle(void *setting);
+
+ACH_ComponentHandler ALC5616_handler = {
+    COMPONENT_INACTIVE,
+    0,
+    ALC5616_Enable,
+    ALC5616_Disable,
+    ALC5616_Reset,
+    ALC5616_GetTypeAndID,
+    ALC5616_Handle,
+};
+
+extern int I2CInit(void);
+extern int I2CDeInit(void);
+extern void I2CWrite(unsigned char numid, unsigned short value);
+extern void I2CBurstWrite(unsigned char numid, unsigned char size, unsigned char *value);
+extern void I2CRead(unsigned char numid, unsigned char *value);
+extern void I2CBurstRead(unsigned char numid, unsigned char *value, int size, int offset);
+
+#ifdef PXA1826_AUDIO
+#ifndef ACM_ALSA_INIT
+#define ACM_ALSA_INIT
+#endif
+#endif
+
+#ifdef DEBUG_FAKE_ACH
+#undef ACM_ALSA_INIT
+#endif
+
+
+static void ALC5616_RegSet(unsigned char numid, unsigned short value) {
+#ifndef DEBUG_FAKE_ACH
+    I2CWrite(numid, value);
+#else
+    LOGD(ALC5616_RegSet, "  FAKE_ACH: %s(0x%x, 0x%x)", __FUNCTION__, numid, value);
+#endif
+}
+
+static void ALC5616_RegBurstSet(unsigned char numid, unsigned char size, unsigned char *value) {
+#ifndef DEBUG_FAKE_ACH
+    I2CBurstWrite(numid, size, value);
+#else
+    LOGD(ALC5616_RegBurstSet, "  FAKE_ACH: %s(0x%x, 0x%x, ..)", __FUNCTION__, numid, size);
+#endif
+}
+
+void ALC5616_RegGet(unsigned char numid, unsigned char *value) {
+#ifndef DEBUG_FAKE_ACH
+    I2CRead(numid, value);
+#else
+    LOGD(ALC5616_RegGet, "  FAKE_ACH: %s(0x%x, ..)", __FUNCTION__, numid);
+#endif
+}
+
+void ALC5616_RegBurstGet(unsigned char numid, unsigned char *value, int size, int offset) {
+#ifndef DEBUG_FAKE_ACH
+    I2CBurstRead(numid, value, size, offset);
+#else
+    LOGD(ALC5616_RegBurstGet, "  FAKE_ACH: %s(0x%x, .., 0x%x, 0x%x)", __FUNCTION__, numid, size, offset);
+#endif
+}
+
+static void ALC5616_ResetRegCache() {
+    int size = sizeof(reg_cache) / sizeof(reg_cache[0]);
+    int i = 0;
+
+    for (i = 0; i < size; i++) {
+        reg_cache[i].reg_value = reg_cache[i].reg_default;
+    }
+}
+
+unsigned char ALC5616_GetRegNumId(unsigned char reg_index) {
+    unsigned char i = 0;
+
+    for (i = 0; i < NUM_OF_REGS; i++) {
+        if (reg_cache[i].reg_index == reg_index) {
+            return REG_NUMID_BASE + i;
+        }
+    }
+
+    return 0;
+}
+
+//--------------------------------------------------------------
+//-------- External ACH APIs
+//--------------------------------------------------------------
+#ifdef ACM_ALSA_INIT
+// NOTE about pair Enable/Disable
+//  On startup Disable could be called without Enable as Init/Reset sequence
+//  Let's "force" I2CInit() for first only Disable without Enable
+//
+static int _acm_initialized = 0;
+#endif
+
+static void ALC5616_Enable(void) {
+    LOGI(ALC5616_Enable, "%s: enable ALC5616 component", __FUNCTION__);
+
+#ifdef ACM_ALSA_INIT
+    LOGI(ALC5616_Enable, "%s: _acm_initialized=%d!", __FUNCTION__, _acm_initialized);
+    _acm_initialized = 1;
+    I2CInit(); //adaptor to alsa-mixer
+#endif
+
+}
+
+static void ALC5616_Disable(void) {
+    LOGI(ALC5616_Disable, "%s: disable ALC5616 component", __FUNCTION__);
+
+#ifdef ACM_ALSA_INIT
+    if (!_acm_initialized) {
+        _acm_initialized = 1;
+        I2CInit(); //adaptor to alsa-mixer
+    }
+#endif
+
+#ifdef ACM_ALSA_INIT
+    I2CDeInit(); //adaptor to alsa-mixer
+#endif
+}
+
+static void ALC5616_Reset(void) {
+    LOGI(ALC5616_Reset, "%s: Reset ALC5616 registers!", __FUNCTION__);
+    int size = sizeof(reg_cache) / sizeof(reg_cache[0]);
+    int size_col = sizeof(reg_cache[0]) / sizeof(unsigned char);
+    int i, k = 0;
+    unsigned char j, numid, value, cache_idx;
+    ALC5616_RegisterCache reg_cache_inorder[size];
+
+#ifdef ACM_ALSA_INIT
+    I2CInit(); //make sure to enable mixer before and close after this operation
+#endif
+
+#ifdef ACM_ALSA_INIT
+    I2CDeInit(); //make sure to enable mixer before and close after this operation
+#endif
+}
+
+static void ALC5616_GetTypeAndID(int *type, unsigned char *id) {
+#ifdef ACM_ALSA_INIT
+    I2CInit(); //make sure to enable mixer before and close after this operation
+#endif
+    LOGI(Elba_GetTypeAndID, "%s: Get type and ID for elba component", __FUNCTION__);
+    *type = COMPONENT_TYPE_CODEC;
+    ALC5616_RegGet(ALC5616_ID_REG, id);
+#ifdef ACM_ALSA_INIT
+    I2CDeInit(); //make sure to enable mixer before and close after this operation
+#endif
+}
+
+static ACH_ReturnCode ALC5616_Handle(void *setting) {
+    ACH_ComponentParameter *param = (ACH_ComponentParameter *)setting;
+    unsigned short i = 0;
+    unsigned short numid, value, cache_idx;
+
+    if (param && param->i2c.reg_value) {
+        numid = ALC5616_GetRegNumId(param->i2c.reg_index);
+
+        LOGI(ALC5616_Handle, "%s: REG_NUMID_BASE=%d, numid=%d. set register 0x%lx values:0x%lx ",
+                __FUNCTION__, REG_NUMID_BASE, numid, param->i2c.reg_index,  *(param->i2c.reg_value));
+
+        if (numid > 0) {
+            if (param->i2c.length == 2) {
+                //compare with register cache
+                cache_idx = numid - REG_NUMID_BASE;
+                value = (*param->i2c.reg_value);
+
+#ifdef DEBUG_ALC5616
+                LOGI(ALC5616_Handle, "%s: cache_idx=%d, numid=%d. set register 0x%lx [0x%lx --> 0x%lx]",
+                        __FUNCTION__,
+                        cache_idx,
+                        numid,
+                        param->i2c.reg_index,
+                        reg_cache[cache_idx].reg_value,
+                        value);
+#endif
+                reg_cache[cache_idx].reg_value = value;
+                ALC5616_RegSet(numid, value);
+
+            } else if (param->i2c.length > 2) {
+                //FIXME current no register cache is provided for mixer/eq configuration
+#ifdef DEBUG_ALC5616
+                LOGI(ALC5616_Handle2, "%s: numid=%d. set register 0x%lx values:", __FUNCTION__, numid, param->i2c.reg_index);
+                for (i = 0; i < param->i2c.length; i++) {
+                    LOGI(ALC5616_Handle3, "%s: \t\t\t    -->0x%lx", __FUNCTION__, param->i2c.reg_value[i]);
+                }
+#endif
+
+                ALC5616_RegBurstSet(numid, param->i2c.length, param->i2c.reg_value);
+            }
+        }
+    }
+
+    return ACH_RC_OK;
+}
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);
+}
+
diff --git a/marvell/services/audio/libacm/acm/src/acm_aph_old.c b/marvell/services/audio/libacm/acm/src/acm_aph_old.c
new file mode 100644
index 0000000..e5ea4ed
--- /dev/null
+++ b/marvell/services/audio/libacm/acm/src/acm_aph_old.c
@@ -0,0 +1,2381 @@
+/*
+* 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 <stdlib.h>
+#include <cutils/log.h>
+#include "acm_xml_parser.h"
+#include "acm_param.h"
+
+#ifdef PXA1826_AUDIO
+#include "audio_stub.h"
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#endif
+
+//--------------------------------------------------------------
+//-------- Global Information Tables
+//--------------------------------------------------------------
+static APH_BasicElementsTable *basic_element_table = NULL;
+static APH_PathConfigurationTable *path_config_table = NULL;
+static APH_GainConfigurationTable *gain_config_table = NULL;
+static APH_CoeffConfigurationTable *coeff_config_table = NULL;
+static APH_EQCoeffConfigurationTable *coeff_eqconfig_table = NULL;
+
+static APH_PathStatus *path_status_table = NULL;
+static unsigned short *active_path_table = NULL;
+static unsigned short active_path_number = 0;
+
+static int modem_is_wb = 0, modem_is_master = 0;
+    
+extern ACH_ComponentHandler elba_handler;
+extern ACH_ComponentHandler ustica_handler;
+extern ACH_ComponentHandler PMIC_handler;
+extern ACH_ComponentHandler CODEC_handler;
+#ifdef WITH_GPIO_SPKR_SWITCH
+extern ACH_ComponentHandler gpio_handler;
+#endif
+static APH_ACHComponent ACH_component_table[] = {
+/* considering existing xml files' config, not unify ELBA & USTICA name for compability */
+#ifdef PMIC_USTICA
+    {USTICA, I2C, &ustica_handler},
+#endif
+#ifdef CODEC_ELBA
+    {ELBA, I2C, &elba_handler},
+#endif
+#ifdef CODEC_GELATO
+    {CODEC, I2C, &CODEC_handler},
+#endif
+#ifdef PMIC_PIANOSA
+    {PMIC, I2C, &PMIC_handler},
+#endif
+#ifdef WITH_GPIO_SPKR_SWITCH
+    {GPIO_PORT, GPIO, &gpio_handler},
+#endif
+    //insert ACH components below for extension
+};
+
+//--------------------------------------------------------------
+//-------- Internal Used Functions
+//--------------------------------------------------------------
+unsigned short _get_ctl_unit_id(const unsigned char *name, const APH_BasicElementsTable *basic_info) {
+    APH_RegisterInfo *reg_info = basic_info->reg_info;
+    while (reg_info) {
+        if (strcmp((const char *)name, (const char *)reg_info->field) == 0) {
+            return reg_info->control_unit_id;
+        }
+        reg_info = reg_info->next;
+    }
+
+    APH_HCIInfo *hci_info = basic_info->hci_info;
+    while (hci_info) {
+        if (strcmp((const char *)name, (const char *)hci_info->name) == 0) {
+            return hci_info->control_unit_id;
+        }
+        hci_info = hci_info->next;
+    }
+
+    APH_GPIOInfo *gpio_info = basic_info->gpio_info;
+    while (gpio_info) {
+        if (strcmp((const char *)name, (const char *)gpio_info->name) == 0) {
+            return gpio_info->control_unit_id;
+        }
+        gpio_info = gpio_info->next;
+    }
+
+    return INVALID_CTL_UNIT_ID;
+}
+
+const unsigned char *_get_ctl_unit_name(unsigned short id, const APH_BasicElementsTable *basic_info) {
+    APH_RegisterInfo *reg_info = basic_info->reg_info;
+    while (reg_info) {
+        if (id == reg_info->control_unit_id) {
+            return reg_info->field;
+        }
+        reg_info = reg_info->next;
+    }
+
+    APH_HCIInfo *hci_info = basic_info->hci_info;
+    while (hci_info) {
+        if (id == hci_info->control_unit_id) {
+            return hci_info->name;
+        }
+        hci_info = hci_info->next;
+    }
+
+    APH_GPIOInfo *gpio_info = basic_info->gpio_info;
+    while (gpio_info) {
+        if (id == gpio_info->control_unit_id) {
+            return gpio_info->name;
+        }
+        gpio_info = gpio_info->next;
+    }
+
+    return NULL;
+}
+
+int _get_ctl_unit_ref_cnt(unsigned short id, const APH_BasicElementsTable *basic_info) {
+    APH_RegisterInfo *reg_info = basic_info->reg_info;
+    while (reg_info) {
+        if (id == reg_info->control_unit_id) {
+            // filter coefficient, force and gain type register
+            if (reg_info->field_type == REG_FIELD_TYPE_COEFF ||
+                reg_info->field_type == REG_FIELD_TYPE_FORCE ||
+                reg_info->field_type == REG_FIELD_TYPE_GAIN) {
+                return 0;
+            }
+
+            return reg_info->ref_cnt;
+        }
+        reg_info = reg_info->next;
+    }
+
+    APH_HCIInfo *hci_info = basic_info->hci_info;
+    while (hci_info) {
+        if (id == hci_info->control_unit_id) {
+            return hci_info->ref_cnt;
+        }
+        hci_info = hci_info->next;
+    }
+
+    APH_GPIOInfo *gpio_info = basic_info->gpio_info;
+    while (gpio_info) {
+        if (id == gpio_info->control_unit_id) {
+            return gpio_info->ref_cnt;
+        }
+        gpio_info = gpio_info->next;
+    }
+
+    return -1;
+}
+
+unsigned char _get_ctl_unit_field_type(unsigned short id, const APH_BasicElementsTable *basic_info) {
+    APH_RegisterInfo *reg_info = basic_info->reg_info;
+    while (reg_info) {
+        if (id == reg_info->control_unit_id) {
+                return reg_info->field_type;
+        }
+        reg_info = reg_info->next;
+    }
+    return REG_FIELD_TYPE_INVALID;
+}
+
+void _update_ctl_unit_ref_cnt(unsigned short id, const APH_BasicElementsTable *basic_info, unsigned char operation) {
+    APH_RegisterInfo *reg_info = basic_info->reg_info;
+
+    if (operation != ENABLE && operation != DISABLE){
+        return;
+    }
+    while (reg_info) {
+        // ignore gain type register
+        if ((id == reg_info->control_unit_id) && (reg_info->field_type != REG_FIELD_TYPE_GAIN)) {
+            if (operation == ENABLE)
+                reg_info->ref_cnt++;
+            else if (reg_info->ref_cnt > 0)
+                reg_info->ref_cnt--;
+
+            return;
+        }
+        reg_info = reg_info->next;
+    }
+
+    APH_HCIInfo *hci_info = basic_info->hci_info;
+    while (hci_info) {
+        if (id == hci_info->control_unit_id) {
+            if (operation == ENABLE)
+                hci_info->ref_cnt++;
+            else if (hci_info->ref_cnt > 0)
+                hci_info->ref_cnt--;
+
+            return;
+        }
+        hci_info = hci_info->next;
+    }
+
+    APH_GPIOInfo *gpio_info = basic_info->gpio_info;
+    while (gpio_info) {
+        if (id == gpio_info->control_unit_id) {
+            if (operation == ENABLE)
+                gpio_info->ref_cnt++;
+            else if (gpio_info->ref_cnt > 0)
+                gpio_info->ref_cnt--;
+
+            return;
+        }
+        gpio_info = gpio_info->next;
+    }
+
+    return;
+}
+
+void _reset_ctl_unit_ref_cnt(const APH_BasicElementsTable *basic_info) {
+    APH_RegisterInfo *reg_info = basic_info->reg_info;
+
+    while (reg_info) {
+        reg_info->ref_cnt = 0;
+        reg_info = reg_info->next;
+    }
+
+    APH_HCIInfo *hci_info = basic_info->hci_info;
+    while (hci_info) {
+        hci_info->ref_cnt = 0;
+        hci_info = hci_info->next;
+    }
+
+    APH_GPIOInfo *gpio_info = basic_info->gpio_info;
+    while (gpio_info) {
+        gpio_info->ref_cnt = 0;
+        gpio_info = gpio_info->next;
+    }
+
+    return;
+}
+
+unsigned short _get_path_id(const unsigned char *path_identifier, APH_PathConfigurationTable *path_info) {
+    APH_PathIdMapping *mapping = path_info->path_id_mapping;
+    if(path_identifier == NULL)
+        return INVALID_PATH_ID;
+    while (mapping) {
+        if (strcmp((const char *)path_identifier, (const char *)mapping->path_identifier) == 0) {
+            return mapping->path_id;
+        }
+
+        mapping = mapping->next;
+    }
+
+    return INVALID_PATH_ID;
+}
+
+const unsigned char *_get_path_identifier(unsigned short path_id, APH_PathConfigurationTable *path_info) {
+    APH_PathIdMapping *mapping = path_info->path_id_mapping;
+
+    while (mapping) {
+        if (mapping->path_id == path_id) {
+            return mapping->path_identifier;
+        }
+
+        mapping = mapping->next;
+    }
+
+    return NULL;
+}
+
+static void _free_basic_element_table(APH_BasicElementsTable *table) {
+    if (table->reg_info) {
+        APH_RegisterInfo *reg_info = table->reg_info;
+        APH_RegisterInfo *cur_reg_info = reg_info;
+        while (reg_info) {
+            reg_info = reg_info->next;
+            free(cur_reg_info);
+            cur_reg_info = reg_info;
+        }
+    }
+
+    if (table->hci_info) {
+        APH_HCIInfo *hci_info = table->hci_info;
+        APH_HCIInfo *cur_hci_info = hci_info;
+        while (hci_info) {
+            hci_info = hci_info->next;
+            free(cur_hci_info);
+            cur_hci_info = hci_info;
+        }
+    }
+
+    if (table->gpio_info) {
+        APH_GPIOInfo *gpio_info = table->gpio_info;
+        APH_GPIOInfo *cur_gpio_info = gpio_info;
+        while (gpio_info) {
+            gpio_info = gpio_info->next;
+            free(cur_gpio_info);
+            cur_gpio_info = gpio_info;
+        }
+    }
+
+    free(table);
+}
+
+static void _free_component_config(APH_ComponentConfiguration *config) {
+    APH_ControlUnitConfiguration *ctl_unit_config = config->component_ctl_unit_array;
+    APH_ControlUnitConfiguration *cur_ctl_unit_config = ctl_unit_config;
+
+    while (ctl_unit_config) {
+        ctl_unit_config = ctl_unit_config->next;
+
+        if (config->component_ctl_protocol == I2C ||
+            config->component_ctl_protocol == ACIPC) {
+            //don't free gain entry here since it will be freed in other place
+            if (cur_ctl_unit_config->i2c_unit.reg_type != REG_FIELD_TYPE_GAIN) {
+                free(cur_ctl_unit_config->i2c_unit.reg_value);
+            }
+        } else if (config->component_ctl_protocol == HCI) {
+            free(cur_ctl_unit_config->hci_unit.hci_parameters);
+        }
+
+        free(cur_ctl_unit_config);
+        cur_ctl_unit_config = ctl_unit_config;
+    }
+
+    free(config);
+}
+
+static void _free_path_config(APH_PathConfiguration *config) {
+    APH_ComponentConfiguration *component_config = config->path_component_array;
+    APH_ComponentConfiguration *cur_component_config = component_config;
+
+    while (component_config) {
+        component_config = component_config->next;
+        _free_component_config(cur_component_config);
+        cur_component_config = component_config;
+    }
+
+    free(config);
+}
+
+static void _free_path_id_mapping(APH_PathIdMapping *mapping) {
+    APH_PathIdMapping *cur_mapping = mapping;
+    while (mapping) {
+        mapping = mapping->next;
+        free(cur_mapping);
+        cur_mapping = mapping;
+    }
+}
+
+static void _free_path_config_table(APH_PathConfigurationTable *table) {
+    //free path id mapping
+    _free_path_id_mapping(table->path_id_mapping);
+
+    //free path configuration
+    APH_PathConfiguration *path_config = table->path_configuration;
+    APH_PathConfiguration *cur_path_config = path_config;
+    while (path_config) {
+        path_config = path_config->next;
+        _free_path_config(cur_path_config);
+        cur_path_config = path_config;
+    }
+
+    //free path configuration table
+    free(table);
+}
+
+static void _free_gain_config(APH_GainConfiguration *config) {
+    APH_VolumeGainMapping *volume_gain_mapping = config->volume_gain_mapping;
+    APH_VolumeGainMapping *cur_volume_gain_mapping = volume_gain_mapping;
+
+    while (volume_gain_mapping) {
+        volume_gain_mapping = volume_gain_mapping->next;
+        free(cur_volume_gain_mapping);
+        cur_volume_gain_mapping = volume_gain_mapping;
+    }
+
+    free(config);
+}
+
+static void _free_gain_config_table(APH_GainConfigurationTable *table) {
+    APH_GainConfiguration *gain_config = table->gain_configuration;
+    APH_GainConfiguration *cur_gain_config = gain_config;
+
+    while (gain_config) {
+        gain_config = gain_config->next;
+        _free_gain_config(cur_gain_config);
+        cur_gain_config = gain_config;
+    }
+
+    free(table);
+}
+
+static void _free_coeff_group_config(APH_Coefficient_Group *coeff_grp) {
+    APH_Coefficient *coeff = coeff_grp->coefficients;
+    APH_Coefficient *cur_coeff = coeff;
+
+    while (coeff) {
+        coeff = coeff->next;
+        free(cur_coeff);
+        cur_coeff = coeff;
+    }
+    free(coeff_grp);
+}
+
+static void _free_coeff_config(APH_CoeffConfiguration *coeff_config) {
+    APH_Coefficient_Group *coeff_grp = coeff_config->coefficients_group;
+    APH_Coefficient_Group *cur_coeff_grp = coeff_grp;
+
+    while (coeff_grp){
+        coeff_grp = coeff_grp->next;
+        _free_coeff_group_config(cur_coeff_grp);
+        cur_coeff_grp = coeff_grp;
+    }
+    free(coeff_config);
+}
+
+static void _free_coeff_config_table(APH_CoeffConfigurationTable *table) {
+    APH_CoeffConfiguration *coeff_config = table->coeff_configuration;
+    APH_CoeffConfiguration *cur_coeff_config = coeff_config;
+
+    while (coeff_config) {
+        coeff_config = coeff_config->next;
+        _free_coeff_config(cur_coeff_config);
+        cur_coeff_config = coeff_config;
+    }
+
+    free(table);
+}
+
+static void _free_eqcoeff_config_table(APH_EQCoeffConfigurationTable *table) {
+    APH_EQCoefficient *eq_coeff_config = table->eq_coeff_configuration;
+    APH_EQCoefficient *cur_eq_coeff_config = eq_coeff_config;
+
+    while (eq_coeff_config) {
+        eq_coeff_config = eq_coeff_config->next;
+        free(cur_eq_coeff_config->coeff_filt_addr);
+        free(cur_eq_coeff_config->eq_coeff);
+        if (cur_eq_coeff_config->coeff_mngr) {
+            APH_ControlUnitConfiguration *ctl_unit_config = eq_coeff_config->coeff_mngr;
+            APH_ControlUnitConfiguration *cur_ctl_unit_config = ctl_unit_config;
+            while(cur_ctl_unit_config){
+                ctl_unit_config = cur_ctl_unit_config->next;
+                free(cur_ctl_unit_config);
+                cur_ctl_unit_config = ctl_unit_config;
+            }
+        }
+
+        free(cur_eq_coeff_config);
+        cur_eq_coeff_config = eq_coeff_config;
+    }
+
+    free(table);
+}
+
+static int _add_new_path_id(const unsigned char *name, APH_PathConfigurationTable *table) {
+    APH_PathIdMapping *path_id_mapping = (APH_PathIdMapping *)malloc(sizeof(APH_PathIdMapping));
+    if (path_id_mapping == NULL) {
+        LOGE(_add_new_path_id, "%s/L%d: out of memory", __FUNCTION__, __LINE__);
+        return -1;
+    }
+
+    path_id_mapping->path_id = table->path_number + 1;
+    strcpy((char *)path_id_mapping->path_identifier, (const char *)name);
+    table->path_number++;
+
+    APH_PathIdMapping *last_path_id_mapping = table->path_id_mapping;
+    while (last_path_id_mapping->next) last_path_id_mapping = last_path_id_mapping->next;
+    last_path_id_mapping->next = path_id_mapping;
+
+    return 0;
+}
+
+static void _align_path_id(APH_PathConfigurationTable *old_config, APH_PathConfigurationTable *new_config) {
+    //align path id mapping
+    APH_PathIdMapping *old_mapping = old_config->path_id_mapping;
+    APH_PathIdMapping *new_mapping = new_config->path_id_mapping;
+    while (new_mapping) {
+        old_mapping = old_config->path_id_mapping;
+        while (old_mapping) {
+            if (strcmp((const char *)old_mapping->path_identifier, (const char *)new_mapping->path_identifier) == 0) {
+                break;
+            }
+
+            old_mapping = old_mapping->next;
+        }
+
+        if (old_mapping) {
+            //same path, update path id in new configuration
+            new_mapping->path_id = old_mapping->path_id;
+        } else {
+            //new path, dispatch new path id and update both old and new configuration
+            if (_add_new_path_id(new_mapping->path_identifier, old_config) == 0) {
+                new_mapping->path_id = _get_path_id(new_mapping->path_identifier, old_config);
+            }
+        }
+
+        new_mapping = new_mapping->next;
+    }
+
+    //update reference path id in new configuration
+    APH_PathConfiguration *path_config = new_config->path_configuration;
+    while (path_config) {
+        if (path_config->path_ref_id != INVALID_PATH_ID) {
+            const unsigned char *path_identifier = _get_path_identifier(path_config->path_ref_id, new_config);
+            path_config->path_ref_id = _get_path_id(path_identifier, old_config);
+        }
+
+        path_config = path_config->next;
+    }
+}
+
+static void _add_new_path_config(APH_PathConfigurationTable *table, APH_PathConfiguration *path_config) {
+    APH_PathConfiguration *last_path_config = table->path_configuration;
+    while (last_path_config->next) last_path_config = last_path_config->next;
+    last_path_config->next = path_config;
+}
+
+static void _replace_old_path_config(APH_PathConfigurationTable *table, APH_PathConfiguration *path_config) {
+    APH_PathConfiguration *old_path_config = table->path_configuration;
+    APH_PathConfiguration *prev_old_path_config = old_path_config;
+
+    while (old_path_config) {
+        if ((path_config->path_id == old_path_config->path_id) &&
+            (path_config->path_op_id == old_path_config->path_id)) {
+            break;
+        }
+
+        prev_old_path_config = old_path_config;
+        old_path_config = old_path_config->next;
+    }
+
+    if (old_path_config) {
+        //same operation, replace old configuration
+        path_config->next = old_path_config->next;
+        if (old_path_config == prev_old_path_config) {
+            table->path_configuration = path_config;
+        } else {
+            prev_old_path_config->next = path_config;
+        }
+        _free_path_config(old_path_config);
+    } else {
+        //new operation, insert new configuration
+        prev_old_path_config->next = path_config;
+    }
+}
+
+static void _update_path_configuration(APH_PathConfigurationTable *old_config, APH_PathConfigurationTable *new_config) {
+    //align path id between old and new configuration
+    _align_path_id(old_config, new_config);
+
+    //update path configuration
+    APH_PathConfiguration *new_config_entry = new_config->path_configuration;
+    APH_PathConfiguration *old_config_entry = old_config->path_configuration;
+    APH_PathConfiguration *tmp_config_entry = NULL;
+    while (new_config_entry) {
+        old_config_entry = old_config->path_configuration;
+        while (old_config_entry) {
+            if (old_config_entry->path_id == new_config_entry->path_id) {
+                break;
+            }
+
+            old_config_entry = old_config_entry->next;
+        }
+
+        tmp_config_entry = new_config_entry->next;
+        if (!old_config_entry) {
+            //new path configuration, add to old table
+            _add_new_path_config(old_config, new_config_entry);
+        } else {
+            //old path configuration, replace old entry in old table
+            _replace_old_path_config(old_config, new_config_entry);
+        }
+
+        new_config_entry = tmp_config_entry;
+    }
+
+    //free new configuration
+    _free_path_id_mapping(new_config->path_id_mapping);
+    free(new_config);
+}
+
+static int _init_path_status_tables(unsigned short path_number) {
+    unsigned short i = 0;
+
+    path_status_table = (APH_PathStatus *)malloc(path_number * sizeof(APH_PathStatus));
+    if (path_status_table == NULL) {
+        LOGE(_init_path_status_tables, "%s/L%d: out of memory", __FUNCTION__, __LINE__);
+        return -1;
+    }
+
+    for (i = 0; i < path_number; i++) {
+        path_status_table[i].order = INVALID_ORDER_INDEX;
+        path_status_table[i].value = 0;
+        path_status_table[i].mute = 0;
+    }
+
+    active_path_table = (unsigned short *)malloc(path_number * sizeof(unsigned short));
+    if (active_path_table == NULL) {
+        LOGE(_init_path_status_tables1, "%s/L%d: out of memory", __FUNCTION__, __LINE__);
+        return -1;
+    }
+    memset(active_path_table, 0, path_number * sizeof(unsigned short));
+
+    return 0;
+}
+
+static APH_PathConfiguration *_get_path_config(unsigned short path_id, unsigned char operation, unsigned short ref_path_id);
+static ACM_ReturnCode _check_register_misc(APH_ControlUnitConfiguration *config, unsigned char protocol, unsigned int value);
+
+static void _update_ref_count(unsigned short path_id, unsigned short ref_path_id, unsigned char operation, unsigned int value) {
+    APH_PathConfiguration *path_config = _get_path_config(path_id, operation, INVALID_PATH_ID);
+    APH_PathConfiguration *ref_path_config = NULL;
+    APH_ComponentConfiguration *component_config = NULL;
+
+
+    if (operation == ENABLE || operation == DISABLE) {
+        if (path_config) {
+            component_config = path_config->path_component_array;
+            while (component_config) {
+                APH_ControlUnitConfiguration *ctl_unit_config = component_config->component_ctl_unit_array;
+                while (ctl_unit_config) {
+                    /*
+                    * update the reference count, for enable, ref_cnt++, for
+                    * disable, ref_cnt--
+                    */
+                    if (component_config->component_id != DELAY) {
+                        if (_check_register_misc(ctl_unit_config, component_config->component_ctl_protocol, value) == ACM_RC_OK) {
+                            _update_ctl_unit_ref_cnt(ctl_unit_config->control_unit_id, basic_element_table, operation);
+                        }
+                    }
+                    ctl_unit_config = ctl_unit_config->next;
+                }
+                component_config = component_config->next;
+            }
+        }
+    } else if (operation == SWITCH) {
+        path_config = _get_path_config(path_id, ENABLE, INVALID_PATH_ID);
+        ref_path_config = _get_path_config(ref_path_id, DISABLE, INVALID_PATH_ID);
+        if (ref_path_config) {
+            component_config = ref_path_config->path_component_array;
+            while (component_config) {
+                APH_ControlUnitConfiguration *ctl_unit_config = component_config->component_ctl_unit_array;
+                while (ctl_unit_config) {
+                    if (component_config->component_id != DELAY) {
+                        if (_check_register_misc(ctl_unit_config, component_config->component_ctl_protocol, value) == ACM_RC_OK) {
+                            operation = DISABLE;
+                            _update_ctl_unit_ref_cnt(ctl_unit_config->control_unit_id, basic_element_table, operation);
+                        }
+                    }
+                    ctl_unit_config = ctl_unit_config->next;
+                }
+                component_config = component_config->next;
+            }
+        }
+        if (path_config) {
+            component_config = path_config->path_component_array;
+            while (component_config) {
+                APH_ControlUnitConfiguration *ctl_unit_config = component_config->component_ctl_unit_array;
+                while (ctl_unit_config) {
+                    if (component_config->component_id != DELAY) {
+                        if (_check_register_misc(ctl_unit_config, component_config->component_ctl_protocol, value) == ACM_RC_OK) {
+                            operation = ENABLE;
+                            _update_ctl_unit_ref_cnt(ctl_unit_config->control_unit_id, basic_element_table, operation);
+                        }
+                    }
+                    ctl_unit_config = ctl_unit_config->next;
+                }
+                component_config = component_config->next;
+            }
+        }
+    } else {
+        return;
+    }
+
+    /* reset the reference count */
+    if (active_path_number == 0){
+        _reset_ctl_unit_ref_cnt(basic_element_table);
+    }
+    return;
+}
+
+static ACH_ComponentHandler *_get_component_handler(unsigned char component_id, unsigned char component_ctl_protocol);
+static ACH_ComponentParameter *_get_component_parameter(APH_ControlUnitConfiguration *config, unsigned char ctl_protocol,
+                                                        unsigned char *volume, unsigned char inverse);
+
+static void _set_eq_coefficiency(APH_EQCoeffConfigurationTable *table){
+
+    if (table == NULL)
+        return;
+
+    APH_EQCoefficient *eq_coeff_config = table->eq_coeff_configuration;
+
+    ACH_ComponentHandler *component_handler =
+            _get_component_handler(table->component_id, table->component_ctl_protocol);
+
+    if (component_handler == NULL){
+        LOGE(_set_eq_coefficiency, "%s/L%d: Can not get component handler", __FUNCTION__, __LINE__);
+        return;
+    }
+
+    while (eq_coeff_config)
+    {
+        if (eq_coeff_config->coeff_filt_addr){
+            ACH_ComponentParameter *param =
+                _get_component_parameter(eq_coeff_config->coeff_filt_addr, table->component_id, NULL, 0);
+            component_handler->ACH_Handle(param);
+        }
+        if (eq_coeff_config->eq_coeff){
+            ACH_ComponentParameter *param =
+                _get_component_parameter(eq_coeff_config->eq_coeff, table->component_id, NULL, 0);
+            component_handler->ACH_Handle(param);
+        }
+
+        if (eq_coeff_config->coeff_mngr){
+            APH_ControlUnitConfiguration *ctl_unit_config = eq_coeff_config->coeff_mngr;
+            while(ctl_unit_config){
+                ACH_ComponentParameter *param =
+                    _get_component_parameter(ctl_unit_config, table->component_id, NULL, 0);
+                component_handler->ACH_Handle(param);
+
+                ctl_unit_config = ctl_unit_config->next;
+            }
+        }
+
+        eq_coeff_config = eq_coeff_config->next;
+    }
+}
+
+static void _add_new_gain_config(APH_GainConfigurationTable *table, APH_GainConfiguration *gain_config) {
+    APH_GainConfiguration *last_gain_config = table->gain_configuration;
+    while (last_gain_config->next) last_gain_config = last_gain_config->next;
+    last_gain_config->next = gain_config;
+    gain_config->next=NULL;
+}
+
+static void _replace_old_gain_config(APH_GainConfigurationTable *table, APH_GainConfiguration *gain_config) {
+    APH_GainConfiguration *old_gain_config = table->gain_configuration;
+    APH_GainConfiguration *prev_old_gain_config = old_gain_config;
+
+    while (old_gain_config) {
+        if (old_gain_config->path_id == gain_config->path_id &&
+            old_gain_config->component_id == gain_config->component_id &&
+            old_gain_config->gain_id == gain_config->gain_id) {
+            break;
+        }
+
+        prev_old_gain_config = old_gain_config;
+        old_gain_config = old_gain_config->next;
+    }
+
+    if (old_gain_config) {
+        gain_config->next = old_gain_config->next;
+        if (old_gain_config == prev_old_gain_config) {
+            table->gain_configuration = gain_config;
+        } else {
+            prev_old_gain_config->next = gain_config;
+        }
+        _free_gain_config(old_gain_config);
+    }
+}
+
+static void _update_gain_configuration(APH_GainConfigurationTable *old_config, APH_GainConfigurationTable *new_config) {
+    APH_GainConfiguration *new_config_entry = new_config->gain_configuration;
+    APH_GainConfiguration *old_config_entry = old_config->gain_configuration;
+    APH_GainConfiguration *tmp_config_entry = NULL;
+
+    while (new_config_entry) {
+        old_config_entry = old_config->gain_configuration;
+        while (old_config_entry) {
+            if (old_config_entry->path_id == new_config_entry->path_id &&
+                old_config_entry->component_id == new_config_entry->component_id &&
+                old_config_entry->gain_id == new_config_entry->gain_id) {
+                break;
+            }
+
+            old_config_entry = old_config_entry->next;
+        }
+
+        tmp_config_entry = new_config_entry->next;
+        if (!old_config_entry) {
+            //new gain configuration, add to old table
+            _add_new_gain_config(old_config, new_config_entry);
+        } else {
+            //old gain configuration, relpace old entry in old table
+            _replace_old_gain_config(old_config, new_config_entry);
+        }
+
+        new_config_entry = tmp_config_entry;
+    }
+
+    //free new configuration
+    free(new_config);
+}
+
+static void _add_new_coeff_config(APH_CoeffConfigurationTable *table, APH_CoeffConfiguration *coeff_config) {
+    APH_CoeffConfiguration *last_coeff_config = table->coeff_configuration;
+    while (last_coeff_config->next) last_coeff_config = last_coeff_config->next;
+    last_coeff_config->next = coeff_config;
+}
+
+static void _replace_old_coeff_config(APH_CoeffConfigurationTable *table, APH_CoeffConfiguration *coeff_config) {
+    APH_CoeffConfiguration *old_coeff_config = table->coeff_configuration;
+    APH_CoeffConfiguration *prev_old_coeff_config = old_coeff_config;
+
+    while (old_coeff_config) {
+        if (old_coeff_config->path_id == coeff_config->path_id &&
+            old_coeff_config->component_id == coeff_config->component_id &&
+            old_coeff_config->path_op_id == coeff_config->path_op_id){
+            break;
+        }
+
+        prev_old_coeff_config = old_coeff_config;
+        old_coeff_config = old_coeff_config->next;
+    }
+
+    if (old_coeff_config) {
+        coeff_config->next = old_coeff_config->next;
+        if (old_coeff_config == prev_old_coeff_config) {
+            table->coeff_configuration = coeff_config;
+        } else {
+            prev_old_coeff_config->next = coeff_config;
+        }
+        _free_coeff_config(old_coeff_config);
+    }
+}
+
+static void _update_coeff_configuration(APH_CoeffConfigurationTable *old_config, APH_CoeffConfigurationTable *new_config) {
+    APH_CoeffConfiguration *new_config_entry = new_config->coeff_configuration;
+    APH_CoeffConfiguration *old_config_entry = old_config->coeff_configuration;
+    APH_CoeffConfiguration *tmp_config_entry = NULL;
+
+    while (new_config_entry) {
+        old_config_entry = old_config->coeff_configuration;
+        while (old_config_entry) {
+            if (old_config_entry->path_id == new_config_entry->path_id &&
+                old_config_entry->component_id == new_config_entry->component_id &&
+                old_config_entry->path_op_id == new_config_entry->path_op_id) {
+                break;
+            }
+
+            old_config_entry = old_config_entry->next;
+        }
+
+        tmp_config_entry = new_config_entry->next;
+        if (!old_config_entry) {
+            //new coeff configuration, add to old table
+            _add_new_coeff_config(old_config, new_config_entry);
+        } else {
+            //old coeff configuration, relpace old entry in old table
+            _replace_old_coeff_config(old_config, new_config_entry);
+        }
+
+        new_config_entry = tmp_config_entry;
+    }
+
+    //free new configuration
+    free(new_config);
+}
+
+static APH_GainConfiguration *_get_gain_config(
+    unsigned short path_id,
+    unsigned char component_id,
+    unsigned short gain_id,
+    APH_GainConfigurationTable *gain_table) {
+    if (gain_table == NULL) return NULL;
+
+    APH_GainConfiguration *gain_config = gain_table->gain_configuration;
+
+    while (gain_config) {
+        if (gain_config->path_id == path_id &&
+            gain_config->component_id == component_id &&
+            gain_config->gain_id == gain_id) {
+            break;
+        }
+
+        gain_config = gain_config->next;
+    }
+
+    return gain_config;
+}
+
+static void _attach_gain_config_to_path(APH_PathConfigurationTable *path_table, APH_GainConfigurationTable *gain_table) {
+    APH_PathConfiguration *path_config = path_table->path_configuration;
+    while (path_config) {
+        APH_ComponentConfiguration *component_config = path_config->path_component_array;
+        while (component_config) {
+            if (component_config->component_ctl_protocol == I2C ||
+                component_config->component_ctl_protocol == ACIPC) {
+                APH_ControlUnitConfiguration *ctl_unit_config = component_config->component_ctl_unit_array;
+                while (ctl_unit_config) {
+                    if (ctl_unit_config->i2c_unit.reg_type == REG_FIELD_TYPE_GAIN) {
+                        ctl_unit_config->i2c_unit.reg_value = (unsigned char *)_get_gain_config(path_config->path_id,
+                                                                                                component_config->component_id,
+                                                                                                ctl_unit_config->control_unit_id,
+                                                                                                gain_table);
+                        ctl_unit_config->i2c_unit.length = 1;
+                    }
+
+                    ctl_unit_config = ctl_unit_config->next;
+                }
+            }
+
+            component_config = component_config->next;
+        }
+
+        path_config = path_config->next;
+    }
+}
+
+static APH_ControlUnitConfiguration*_get_coeff_config(
+    APH_ControlUnitConfiguration *ctl_unit_config,
+    unsigned short path_id,
+    unsigned short path_op_id,
+    unsigned char component_id,
+    APH_CoeffConfigurationTable *coeff_table) {
+
+    APH_CoeffConfiguration *coeff_config = coeff_table->coeff_configuration;
+    APH_ControlUnitConfiguration *ctl_unit_config_old = ctl_unit_config;
+    unsigned char *coeff_values = NULL;
+
+    while (coeff_config) {
+        if (coeff_config->path_id == path_id &&
+            coeff_config->component_id == component_id &&
+            coeff_config->path_op_id == path_op_id) {
+            break;
+        }
+
+        coeff_config = coeff_config->next;
+    }
+
+    if (coeff_config) {
+        APH_Coefficient_Group *coeff_group_config = coeff_config->coefficients_group;
+        while (coeff_group_config)
+        {
+            if (ctl_unit_config == NULL) {
+                break;
+            }
+
+            ctl_unit_config->i2c_unit.length = coeff_group_config->coeff_value_number;
+            coeff_values = (unsigned char *)malloc((ctl_unit_config->i2c_unit.length)* sizeof(unsigned char));
+            if (coeff_values) {
+                APH_Coefficient *coeff = coeff_group_config->coefficients;
+                unsigned short i = 0;
+                while (coeff) {
+                    coeff_values[i++] = coeff->value;
+                    coeff = coeff->next;
+                }
+                ctl_unit_config->i2c_unit.reg_value = coeff_values;
+            }
+
+            coeff_group_config = coeff_group_config->next;
+            // Allocate another ctrol unit and initialize it
+            if (coeff_group_config){
+                ctl_unit_config = (APH_ControlUnitConfiguration *)malloc(sizeof (APH_ControlUnitConfiguration));
+                if (ctl_unit_config) {
+                    memcpy(ctl_unit_config, ctl_unit_config_old, sizeof(APH_ControlUnitConfiguration));
+                    ctl_unit_config->i2c_unit.length = 0;
+                    ctl_unit_config->i2c_unit.reg_value = NULL;
+                    ctl_unit_config->next = ctl_unit_config_old->next;
+                    ctl_unit_config_old->next = ctl_unit_config;
+                    ctl_unit_config_old = ctl_unit_config;
+                }
+            }
+        }
+    }
+
+    return ctl_unit_config;
+}
+
+static void _attach_coeff_config_to_path(APH_PathConfigurationTable *path_table, APH_CoeffConfigurationTable *coeff_table) {
+    APH_PathConfiguration *path_config = path_table->path_configuration;
+    while (path_config) {
+        APH_ComponentConfiguration *component_config = path_config->path_component_array;
+        while (component_config) {
+            if (component_config->component_ctl_protocol == I2C ||
+                component_config->component_ctl_protocol == ACIPC) {
+                APH_ControlUnitConfiguration *ctl_unit_config = component_config->component_ctl_unit_array;
+                while (ctl_unit_config) {
+                    if (ctl_unit_config->i2c_unit.reg_type == REG_FIELD_TYPE_COEFF) {
+                        // return the last malloc control unit
+                        ctl_unit_config = _get_coeff_config(ctl_unit_config,
+                                          path_config->path_id,
+                                          path_config->path_op_id,
+                                          component_config->component_id,
+                                          coeff_table);
+                    }
+                    if (ctl_unit_config == NULL) {
+                        LOGE(_attach_coeff_config_to_path, "%s/L%d: out of memory", __FUNCTION__, __LINE__);
+                        return;
+                    }
+
+                    ctl_unit_config = ctl_unit_config->next;
+                }
+            }
+
+            component_config = component_config->next;
+        }
+
+        path_config = path_config->next;
+    }
+}
+
+static char *_get_xml_appendix() {
+    int size = sizeof(ACH_component_table) / sizeof(ACH_component_table[0]);
+    int i = 0;
+    int type = -1;
+    unsigned char id = 0;
+    char *appendix = (char *)malloc(XML_NAME_LEN);
+    if (appendix) {
+        memset(appendix, 0, XML_NAME_LEN);
+
+        for (i = 0; i < size; i++) {
+            ACH_component_table[i].component_handler->ACH_GetTypeAndID(&type, &id);
+            if (type == COMPONENT_TYPE_CODEC && id == 3) {
+                // Procida B0
+                memcpy(appendix, "_B0", sizeof("_B0"));
+                break;
+            }
+        }
+    }
+
+    return appendix;
+}
+static ACH_ComponentHandler *_get_component_handler(unsigned char component_id, unsigned char component_ctl_protocol) {
+    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 &&
+            ACH_component_table[i].component_ctl_protocol == component_ctl_protocol) {
+            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 int _is_path_active(unsigned short path_id) {
+    return (path_status_table[path_id - 1].order==INVALID_ORDER_INDEX ? 0 : 1);
+}
+
+static int _is_path_config_changed(unsigned short path_id, unsigned int value) {
+    return ((path_status_table[path_id - 1].value & PARAM_MASK) != (value & PARAM_MASK));
+}
+
+static int _is_path_muted(unsigned char path_id) {
+    return path_status_table[path_id - 1].mute;
+}
+
+static int _is_voice_path_active() {
+    unsigned short i = 0;
+    for(i = 0; i < active_path_number; i++) {
+        if(ACM_APHGetPathType(active_path_table[i]) == VOICE_PATH)
+            return 1;
+    }
+    return 0;
+}
+
+static APH_PathConfiguration *_get_path_config(unsigned short path_id, unsigned char operation, unsigned short ref_path_id) {
+    APH_PathConfiguration *path_config = path_config_table->path_configuration;
+
+    while (path_config) {
+        if (path_config->path_id == path_id &&
+            path_config->path_op_id == operation &&
+            path_config->path_ref_id == ref_path_id) {
+            break;
+        }
+
+        path_config = path_config->next;
+    }
+
+    return path_config;
+}
+
+static void _update_active_path_table() {
+    unsigned short i = 0;
+
+    for (i = 0; i < path_config_table->path_number; i++) {
+        if (path_status_table[i].order != INVALID_ORDER_INDEX) {
+            active_path_table[path_status_table[i].order - 1] = i + 1;
+        }
+    }
+#ifdef DEBUG_APH
+    LOGD(_update_active_path_table, "-----Dump Active Path Table (total %d)-----", active_path_number);
+    for (i = 0; i < active_path_number; i++) {
+        LOGD(_update_active_path_table1, "\tActivePath[%d] = %s", i, _get_path_identifier(active_path_table[i], path_config_table));
+    }
+#endif
+}
+
+static void _remove_active_path(unsigned short path_id) {
+    unsigned char order = path_status_table[path_id - 1].order;
+    unsigned short i = 0;
+
+    if (order == INVALID_ORDER_INDEX) {
+        return;
+    }
+
+#ifdef DEBUG_APH
+    LOGI(_remove_active_path, "%s: remove one active path %s", __FUNCTION__, _get_path_identifier(path_id, path_config_table));
+#endif
+
+    //update path status table
+    active_path_number--;
+    path_status_table[path_id - 1].order = INVALID_ORDER_INDEX;
+    path_status_table[path_id - 1].value = 0;
+    path_status_table[path_id - 1].mute = 0;
+
+    if (active_path_number > 0) {
+        for (i = 0; i < path_config_table->path_number; i++) {
+            if (path_status_table[i].order != INVALID_ORDER_INDEX &&
+                path_status_table[i].order > order) {
+                path_status_table[i].order--;
+            }
+        }
+    }
+
+    //update active path table
+    _update_active_path_table();
+
+    //update component reference count (only refer to default enable configuration)
+    APH_PathConfiguration *path_config = _get_path_config(path_id, ENABLE, INVALID_PATH_ID);
+    if (path_config) {
+        APH_ComponentConfiguration *component_config = path_config->path_component_array;
+        while (component_config) {
+            ACH_ComponentHandler *component_handler
+                = _get_component_handler(component_config->component_id, component_config->component_ctl_protocol);
+            if (component_handler) {
+                component_handler->ref_count--;
+            }
+
+            component_config = component_config->next;
+        }
+    }
+#ifdef DEBUG_APH
+    LOGD(_remove_active_path1, "-----Dump Component Reference Count-----");
+    extern void dump_component_ref_count();
+    dump_component_ref_count();
+#endif
+}
+
+static void _add_active_path(unsigned short path_id, unsigned int value) {
+#ifdef DEBUG_APH
+    LOGI(_add_active_path, "%s: add one active path %s, value 0x%x", __FUNCTION__, _get_path_identifier(path_id, path_config_table), value);
+#endif
+
+    //update path status table
+    active_path_number++;
+    path_status_table[path_id - 1].order = active_path_number;
+    path_status_table[path_id - 1].value = value;
+    path_status_table[path_id - 1].mute = 0;
+
+    //update active path table
+    _update_active_path_table();
+
+    //update component reference count (only refer to default enable configuration)
+    APH_PathConfiguration *path_config = _get_path_config(path_id, ENABLE, INVALID_PATH_ID);
+    if (path_config) {
+        APH_ComponentConfiguration *component_config = path_config->path_component_array;
+        while (component_config) {
+            ACH_ComponentHandler *component_handler
+                = _get_component_handler(component_config->component_id, component_config->component_ctl_protocol);
+            if (component_handler) {
+                component_handler->ref_count++;
+            }
+
+            component_config = component_config->next;
+        }
+    }
+#ifdef DEBUG_APH
+    LOGD(_add_active_path1, "-----Dump Component Reference Count-----");
+    extern void dump_component_ref_count();
+    dump_component_ref_count();
+#endif
+}
+
+static void _turn_off_standby_components() {
+    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_handler->ref_count == 0 &&
+            ACH_component_table[i].component_handler->active == COMPONENT_ACTIVE) {
+            ACH_component_table[i].component_handler->ACH_Disable();
+            ACH_component_table[i].component_handler->active = COMPONENT_INACTIVE;
+        }
+    }
+}
+
+static unsigned char *_get_gain_value(APH_GainConfiguration *gain_config, unsigned char *volume) {
+    if (gain_config == NULL || gain_config->volume_gain_mapping == NULL) {
+        return NULL;
+    }
+
+    APH_VolumeGainMapping *volume_gain_mapping = gain_config->volume_gain_mapping;
+    APH_VolumeGainMapping *nearest_mapping = volume_gain_mapping;
+    unsigned char diff = 0;
+    unsigned char min_diff = 0xFF;
+
+    while (volume_gain_mapping) {
+        if (volume_gain_mapping->volume > *volume) {
+            diff = volume_gain_mapping->volume - *volume;
+        } else {
+            diff = *volume - volume_gain_mapping->volume;
+        }
+
+        if (diff < min_diff) {
+            min_diff = diff;
+            nearest_mapping = volume_gain_mapping;
+        }
+
+        volume_gain_mapping = volume_gain_mapping->next;
+    }
+
+#ifdef DEBUG_APH
+    LOGI(_get_gain_value, "%s: req volume=%d, nearest volume=%d, value=0x%lx",
+        __FUNCTION__, *volume, nearest_mapping->volume, nearest_mapping->value);
+#endif
+    *volume = nearest_mapping->volume;
+    return &(nearest_mapping->value);
+}
+
+static ACH_ComponentParameter *_get_component_parameter(
+    APH_ControlUnitConfiguration *config,
+    unsigned char ctl_protocol,
+    unsigned char *volume,
+    unsigned char inverse) {
+    if (config == NULL) return NULL;
+
+    ACH_ComponentParameter *param = (ACH_ComponentParameter *)malloc(sizeof(ACH_ComponentParameter));
+    if (param == NULL) {
+        LOGE(_get_component_parameter, "%s/L%d: out of memory", __FUNCTION__, __LINE__);
+        return NULL;
+    }
+    memset(param, 0, sizeof(ACH_ComponentParameter));
+
+    if (param) {
+        switch (ctl_protocol) {
+        case I2C:
+            param->i2c.reg_index = config->i2c_unit.reg_index;
+            param->i2c.reg_mask = config->i2c_unit.reg_mask;
+            param->i2c.reg_shift = config->i2c_unit.reg_shift;
+            param->i2c.length = config->i2c_unit.length;
+            switch (config->i2c_unit.reg_type) {
+            case REG_FIELD_TYPE_NORMAL:
+            case REG_FIELD_TYPE_FORCE:
+            case REG_FIELD_TYPE_NORMAL | REG_FIELD_TYPE_GAIN:
+                param->i2c.reg_value = config->i2c_unit.reg_value;
+                if (inverse) {
+                    *param->i2c.reg_value = ~(*param->i2c.reg_value);
+                }
+                break;
+            case REG_FIELD_TYPE_GAIN:
+                param->i2c.reg_value =
+                    _get_gain_value((APH_GainConfiguration *)config->i2c_unit.reg_value, volume);
+                break;
+            case REG_FIELD_TYPE_COEFF:
+                param->i2c.reg_value = config->i2c_unit.reg_value;
+                break;
+            default:
+                break;
+            }
+
+            break;
+        case HCI:
+            param->hci.hci_ocf = config->hci_unit.hci_ocf;
+            param->hci.hci_ogf = config->hci_unit.hci_ogf;
+            param->hci.length = config->hci_unit.length;
+            param->hci.hci_parameters = config->hci_unit.hci_parameters;
+            break;
+        case GPIO:
+            param->gpio.gpio_port = config->gpio_unit.gpio_port;
+            param->gpio.gpio_value = config->gpio_unit.gpio_value;
+            break;
+        case SLEEP:
+            param->delay.delay_value = config->delay_unit.delay_value;
+        default:
+            break;
+        }
+    }
+
+    return param;
+}
+
+static ACM_ReturnCode _get_path_direction(const unsigned char *path_identifier, unsigned char *path_direction) {
+    ACM_ReturnCode ret =  ACM_RC_INVALID_PARAMETER;
+    if(path_identifier != NULL) {
+        if(strstr((const char *)path_identifier, "PlayTo") != NULL) {
+            *path_direction = PATH_DIRECTION_OUT;
+            ret = ACM_RC_OK;
+        }
+        if(strstr((const char *)path_identifier, "RecordFrom") != NULL) {
+            *path_direction = PATH_DIRECTION_IN;
+            ret = ACM_RC_OK;
+        }
+    }
+    return ret;
+}
+
+static ACM_ReturnCode _check_register_misc(APH_ControlUnitConfiguration *config, unsigned char protocol, unsigned int value) {
+    ACM_ReturnCode ret =  ACM_RC_OK;
+    unsigned char misc;
+    if (protocol == I2C && config->i2c_unit.reg_misc != REG_MISC_NONE) {
+        misc = config->i2c_unit.reg_misc;
+    } else if (protocol == SLEEP && config->delay_unit.delay_misc != REG_MISC_NONE) {
+        misc = config->delay_unit.delay_misc;
+    } else {
+        return ret;
+    }
+    switch (misc) {
+        case REG_MISC_MIC1:
+            if (!(value & USE_MIC1) || (value & USE_MIC2)) {
+                ret =  ACM_RC_INVALID_PARAMETER;
+            }
+            break;
+        case REG_MISC_MIC2:
+            if (!(value & USE_MIC2) || (value & USE_MIC1)) {
+                ret =  ACM_RC_INVALID_PARAMETER;
+            }
+            break;
+        case REG_MISC_DUAL_MIC:
+            if (!(value & USE_MIC2) || !(value & USE_MIC1)) {
+                ret =  ACM_RC_INVALID_PARAMETER;
+            }
+            break;
+        case REG_MISC_SLAVE:
+            if (!(value & CODEC_SLAVE)) {
+                ret =  ACM_RC_INVALID_PARAMETER;
+            }
+            break;
+        case REG_MISC_MASTER:
+            if (value & CODEC_SLAVE) {
+                ret =  ACM_RC_INVALID_PARAMETER;
+            }
+            break;
+        case REG_MISC_NB_RATE:
+            if (value & CODEC_RATE_WB) {
+                ret =  ACM_RC_INVALID_PARAMETER;
+            }
+            break;
+        case REG_MISC_WB_RATE:
+            if (!(value & CODEC_RATE_WB)) {
+                ret =  ACM_RC_INVALID_PARAMETER;
+            }
+            break;
+        case REG_MISC_FORCE_DELAY:
+            ret = ACM_RC_FORCE_DELAY;
+            break;
+
+        default:
+            LOGE(_check_register_misc, "%s: unknown register misc!!!", __FUNCTION__);
+            break;
+    }
+    return ret;
+}
+
+static void _set_path_configuration(
+    const unsigned char* path,
+    APH_PathConfiguration *path_config,
+    const unsigned char operation,
+    unsigned int value,
+    unsigned char inverse,
+    unsigned char is_switch) {
+
+    unsigned char volume = 0;
+    unsigned char reg_value;
+    unsigned char flush_reg_value[128] = {0};
+    unsigned char force_delay = 0;
+    ACH_ComponentParameter flush_param;
+    volume = (unsigned char)(value & VOLUME_MASK);
+    unsigned short i = 0;
+    unsigned short path_id_fm = INVALID_PATH_ID;
+    unsigned int flag_ignore_HiFiVolumeSet = 0;
+    unsigned int flag_restore_HiFiVolumeSet = 0;
+    const unsigned char* restore_path = NULL;
+    unsigned short restore_path_id = INVALID_PATH_ID;
+    APH_PathConfiguration *restore_path_config = NULL;
+
+    if (!path_config) {
+        LOGE(_set_path_configuration, "%s: path_config is NULL!!!", __FUNCTION__);
+        return;
+    }
+
+    /*this section of code is for fm volume work-round:
+     *1, when both the path of "HiFiPlayTo..."(besides of ForceSpk path) and "FMPlayTo..." are alive, flag_ignore_HiFiVolumeSet is set to 1;
+     *2, the flag is_FmVolume_WorkRound will be used as the condition in "while (component_config)".
+     */
+    if(!strncmp((char *)path,"HiFiPlayTo",10) && strcmp((char *)path,"HiFiPlayToStereoSPKRAndHP") && strcmp((char *)path,"HiFiPlayToSPKRAndHP")){
+        if( (INVALID_PATH_ID != (path_id_fm =_get_path_id((const unsigned char *)"FMPlayToHPAnalog",path_config_table)) && _is_path_active(path_id_fm))  ||
+            (INVALID_PATH_ID != (path_id_fm =_get_path_id((const unsigned char *)"FMPlayToSPKRAnalog",path_config_table)) && _is_path_active(path_id_fm)) ||
+            (INVALID_PATH_ID != (path_id_fm =_get_path_id((const unsigned char *)"FMPlayToStereoSPKRAnalog",path_config_table)) && _is_path_active(path_id_fm)) )
+	    {
+            LOGI(_set_path_configuration1, "%s: use fm volume work-round, set flag_ignore_HiFiVolumeSet to 1",__FUNCTION__);
+	        flag_ignore_HiFiVolumeSet = 1;
+	    }
+    }/*end of fm volume work-round*/
+
+    APH_ComponentConfiguration *component_config = path_config->path_component_array;
+    while (component_config) {
+        ACH_ComponentHandler *component_handler =
+            _get_component_handler(component_config->component_id, component_config->component_ctl_protocol);
+
+        // DELAY module is a special component which doesn't have component handler.
+        // It support misc property and its ctl unit doesn't need ref count;
+        if (component_handler || component_config->component_id == DELAY) {
+            //turn on component if it's inactive
+            if (component_config->component_id != DELAY && component_handler &&
+                component_handler->active == COMPONENT_INACTIVE &&
+                component_handler->ref_count > 0) {
+                component_handler->ACH_Enable();
+                component_handler->active = COMPONENT_ACTIVE;
+            }
+
+            //configure each control unit through component handler
+            APH_ControlUnitConfiguration *ctl_unit_config = component_config->component_ctl_unit_array;
+            memset(&flush_param, 0, sizeof(ACH_ComponentParameter));
+            flush_param.i2c.reg_value = flush_reg_value;
+            while (ctl_unit_config) {
+                // first check FORCE_DELAY misc, it is only used for delay component
+                if (_check_register_misc(ctl_unit_config, component_config->component_ctl_protocol, value) == ACM_RC_FORCE_DELAY) {
+                    force_delay = 1;
+                } else if (_check_register_misc(ctl_unit_config, component_config->component_ctl_protocol, value) != ACM_RC_OK) {
+                    ctl_unit_config = ctl_unit_config->next;
+                    continue;
+                }
+                // ignore when the control unit is used by other paths for disabling
+                if (component_config->component_id != DELAY && operation == DISABLE &&
+                    _get_ctl_unit_ref_cnt(ctl_unit_config->control_unit_id, basic_element_table) > 0){
+                    ctl_unit_config = ctl_unit_config->next;
+                    continue;
+                }
+                // FM volume workaround: ignore set Elba PDM control register (0x23) which used for external classD gain tuning
+                if(1 == flag_ignore_HiFiVolumeSet && component_config->component_id == ELBA && (0x23 == ctl_unit_config->i2c_unit.reg_index)){
+                    LOGI(_set_path_configuration2, "%s: Ignore set PDM control register as FM is alive", __FUNCTION__);
+                    ctl_unit_config = ctl_unit_config->next;
+                    continue;
+                }
+                /* here is fm volume work-round: won't set HiFi gain if the type is REG_FIELD_TYPE_GAIN */
+                if(1 == flag_ignore_HiFiVolumeSet && (REG_FIELD_TYPE_GAIN & ctl_unit_config->i2c_unit.reg_type)){
+                    LOGI(_set_path_configuration3, "%s: Ignore set HiFi volume as FM is alive", __FUNCTION__);
+                    ctl_unit_config = ctl_unit_config->next;
+                    continue;
+                }/*end of fm volume work-round*/
+                if(1 == flag_restore_HiFiVolumeSet && REG_FIELD_TYPE_GAIN != ctl_unit_config->i2c_unit.reg_type){
+                    LOGI(_set_path_configuration4, "%s: Ignore set non-gain HiFi unit and restore HiFi volume when FM path is dead", __FUNCTION__);
+                    ctl_unit_config = ctl_unit_config->next;
+                    continue;
+                }
+
+                ACH_ComponentParameter *param =
+                    _get_component_parameter(ctl_unit_config, component_config->component_ctl_protocol, &volume, inverse);
+                if (!param) {
+                    LOGE(_set_path_configuration5, "%s: component paramerter is null", __FUNCTION__);
+                    return;
+                }
+
+                if (component_config->component_ctl_protocol == SLEEP) {
+                    if (!is_switch || force_delay) {
+                        LOGD(_set_path_configuration6, "%s: sleep %d ms", __FUNCTION__, param->delay.delay_value);
+                        usleep(param->delay.delay_value * 1000);
+                    }
+                } else if (component_handler && component_config->component_ctl_protocol == I2C) {
+                    if (param->i2c.reg_value == NULL) {
+                        LOGW(_set_path_configuration7, "%s: i2c.reg_value is NULL! Please check register 0x%x and make it align in path config and gain config!",
+                             __FUNCTION__, param->i2c.reg_index);
+                        ctl_unit_config = ctl_unit_config->next;
+                        free(param);
+                        continue;
+                    }
+                    // flush register whose index is different from the previous.
+
+                    // FIXME: assume different fields of one register are configured continuously in xml.
+                    if (param->i2c.length == 1) {
+                        reg_value = (((*param->i2c.reg_value) << param->i2c.reg_shift) & param->i2c.reg_mask);
+                        if ((flush_param.i2c.reg_index != param->i2c.reg_index) || (_get_ctl_unit_field_type(ctl_unit_config->control_unit_id, basic_element_table) == REG_FIELD_TYPE_FORCE)) {
+                            if (flush_param.i2c.length != 0) {
+                                component_handler->ACH_Handle(&flush_param);
+                                flush_param.i2c.length = 0;
+                            }
+                            *flush_param.i2c.reg_value = reg_value;
+                            flush_param.i2c.reg_mask = param->i2c.reg_mask;
+                            flush_param.i2c.reg_index = param->i2c.reg_index;
+                            flush_param.i2c.length = param->i2c.length;
+                        } else {
+                            (*flush_param.i2c.reg_value) |= reg_value;
+                            flush_param.i2c.reg_mask |= param->i2c.reg_mask;
+                        }
+                    } else if (param->i2c.length > 1) {
+                        if (flush_param.i2c.length != 0) {
+                            component_handler->ACH_Handle(&flush_param);
+                            flush_param.i2c.length = 0;
+                        }
+                        component_handler->ACH_Handle(param);
+                    }
+                } else if (component_handler) {
+                    component_handler->ACH_Handle(param);
+                }
+                //inverse again if mute operation changed original value
+                if (inverse) {
+                    *param->i2c.reg_value = ~(*param->i2c.reg_value);
+                }
+                free(param);
+                ctl_unit_config = ctl_unit_config->next;
+            }
+            if (flush_param.i2c.length != 0 && component_handler) {
+                component_handler->ACH_Handle(&flush_param);
+            }
+        }
+
+        component_config = component_config->next;
+    }
+
+    if(operation == DISABLE && !strncmp((char *)path,"FMPlayTo",8)){
+        for (i = 0; i < active_path_number; i++) {
+            restore_path = _get_path_identifier(active_path_table[i], path_config_table);
+            if(restore_path && !strncmp((char *)restore_path,"HiFiPlayTo",10) && strcmp((char *)restore_path,"HiFiPlayToStereoSPKRAndHP")
+                && strcmp((char *)restore_path,"HiFiPlayToSPKRAndHP") ){
+                LOGI(_set_path_configuration8, "%s: set flag_restore_HiFiVolumeSet to 1, the (%d)th active path is %s", __FUNCTION__, i+1, restore_path);
+                flag_restore_HiFiVolumeSet = 1;
+                restore_path_id = _get_path_id(restore_path, path_config_table);
+                if (restore_path_id == INVALID_PATH_ID) {
+                    LOGE(_set_path_configuration9, "%s: invalid path identifier", __FUNCTION__);
+                }
+                restore_path_config = _get_path_config(restore_path_id, ENABLE, INVALID_PATH_ID);
+                if (restore_path_config == NULL) {
+                    LOGE(_set_path_configuration10, "%s: fail to find path configuration", __FUNCTION__);
+                }
+                _set_path_configuration(restore_path, restore_path_config, ENABLE, path_status_table[active_path_table[i] - 1].value, 0, 0);
+                flag_restore_HiFiVolumeSet = 0;
+                break;
+            }
+        }
+    }
+}
+
+//--------------------------------------------------------------
+//-------- Dump Functions for Debug
+//--------------------------------------------------------------
+#ifdef DEBUG_APH /* DEBUG_APH_EXTEND_DUMP !PXA1826_AUDIO */
+#ifdef DEBUG_APH_EXTEND_DUMP
+int debug_aph_dump_ena = 1;
+#else
+int debug_aph_dump_ena;
+#endif
+void dump_basic_elements(APH_BasicElementsTable *table) {
+    APH_RegisterInfo *reg_info = table->reg_info;
+
+    if (!debug_aph_dump_ena)
+        return;
+
+    while (reg_info) {
+        LOGD(dump_basic_elements, "Register: component_id=%d index=0x%lx field=%s field_type=%d "
+            "field_mask=0x%lx field_shift=%d field_default=0x%lx control_unit_id=%d ref_cnt=%d",
+            reg_info->component_id,
+            reg_info->index,
+            reg_info->field,
+            reg_info->field_type,
+            reg_info->field_mask,
+            reg_info->field_shift,
+            reg_info->field_default,
+            reg_info->control_unit_id,
+            reg_info->ref_cnt);
+        reg_info = reg_info->next;
+    }
+
+    APH_HCIInfo *hci_info = table->hci_info;
+    while (hci_info) {
+        LOGD(dump_basic_elements1, "HCI: component_id=%d name=%s ocf=0x%lx ogf=0x%lx length=%d control_unit_id=%d ref_cnt=%d",
+            hci_info->component_id,
+            hci_info->name,
+            hci_info->ocf,
+            hci_info->ogf,
+            hci_info->length,
+            hci_info->control_unit_id,
+            hci_info->ref_cnt);
+        hci_info = hci_info->next;
+    }
+
+    APH_GPIOInfo *gpio_info = table->gpio_info;
+    while (gpio_info) {
+        LOGD(dump_basic_elements2, "GPIO: component_id=%d name=%s port=%d control_unit_id=%d ref_cnt=%d",
+            gpio_info->component_id,
+            gpio_info->name,
+            gpio_info->port,
+            gpio_info->control_unit_id,
+            gpio_info->ref_cnt);
+        gpio_info = gpio_info->next;
+    }
+}
+
+void dump_basic_elements_with_positive_ref_cnt(APH_BasicElementsTable *table) {
+    APH_RegisterInfo *reg_info = table->reg_info;
+
+    if (!debug_aph_dump_ena)
+        return;
+
+    while (reg_info) {
+        if (reg_info->ref_cnt == 0){
+            reg_info = reg_info->next;
+            continue;
+        }
+        LOGD(dump_basic_elements_with_positive_ref_cnt, "Register: component_id=%d index=0x%lx field=%s field_type=%d "
+            "field_mask=0x%lx field_shift=%d field_default=0x%lx control_unit_id=%d ref_cnt=%d",
+            reg_info->component_id,
+            reg_info->index,
+            reg_info->field,
+            reg_info->field_type,
+            reg_info->field_mask,
+            reg_info->field_shift,
+            reg_info->field_default,
+            reg_info->control_unit_id,
+            reg_info->ref_cnt);
+        reg_info = reg_info->next;
+    }
+
+    APH_HCIInfo *hci_info = table->hci_info;
+    while (hci_info) {
+        if (hci_info->ref_cnt == 0){
+            hci_info = hci_info->next;
+            continue;
+        }
+        LOGD(dump_basic_elements_with_positive_ref_cnt1, "HCI: component_id=%d name=%s ocf=0x%lx ogf=0x%lx length=%d control_unit_id=%d ref_cnt=%d",
+            hci_info->component_id,
+            hci_info->name,
+            hci_info->ocf,
+            hci_info->ogf,
+            hci_info->length,
+            hci_info->control_unit_id,
+            hci_info->ref_cnt);
+        hci_info = hci_info->next;
+    }
+
+    APH_GPIOInfo *gpio_info = table->gpio_info;
+    while (gpio_info) {
+        if (gpio_info->ref_cnt == 0){
+            gpio_info = gpio_info->next;
+            continue;
+        }
+        LOGD(dump_basic_elements_with_positive_ref_cnt2, "GPIO: component_id=%d name=%s port=%d control_unit_id=%d ref_cnt=%d",
+            gpio_info->component_id,
+            gpio_info->name,
+            gpio_info->port,
+            gpio_info->control_unit_id,
+            gpio_info->ref_cnt);
+        gpio_info = gpio_info->next;
+    }
+}
+void dump_path_config(APH_PathConfigurationTable *table) {
+    //dump path id mapping
+    APH_PathIdMapping *mapping = table->path_id_mapping;
+
+    if (!debug_aph_dump_ena)
+        return;
+
+    while (mapping) {
+        LOGD(dump_path_config, "PathIdMapping: path_id=%d path_identifier=%s total=%d",
+            mapping->path_id, mapping->path_identifier, table->path_number);
+        mapping = mapping->next;
+    }
+
+    //dump path configuration
+    APH_PathConfiguration *path_config = table->path_configuration;
+    while (path_config) {
+        LOGD(dump_path_config1, "PathConfig: path=%s operation=%s ref_path=%s component_num=%d",
+            _get_path_identifier(path_config->path_id, table),
+            OPERATION_ENUM2STR(path_config->path_op_id),
+            _get_path_identifier(path_config->path_ref_id, table),
+            path_config->path_component_num);
+
+        //dump component configuration
+        APH_ComponentConfiguration *component_config = path_config->path_component_array;
+        while (component_config) {
+            LOGD(dump_path_config2, "\t|-ComponentConfig: component=%s control_protocol=%s control_unit_num=%d",
+                COMPONENT_ENUM2STR(component_config->component_id),
+                PROTOCOL_ENUM2STR(component_config->component_ctl_protocol),
+                component_config->component_ctl_unit_num);
+
+            //dump control unit configuration
+            APH_ControlUnitConfiguration *ctl_unit_config = component_config->component_ctl_unit_array;
+            while (ctl_unit_config) {
+                if (component_config->component_ctl_protocol == I2C ||
+                    component_config->component_ctl_protocol == ACIPC) {
+                    LOGD(dump_path_config3, "\t\t|-RegisterConfig: control_unit=%s reg_index=0x%lx "
+                        "reg_mask=0x%lx reg_shift=0x%lx reg_type=%d length=%d",
+                        _get_ctl_unit_name(ctl_unit_config->control_unit_id, basic_element_table),
+                        ctl_unit_config->i2c_unit.reg_index,
+                        ctl_unit_config->i2c_unit.reg_mask,
+                        ctl_unit_config->i2c_unit.reg_shift,
+                        ctl_unit_config->i2c_unit.reg_type,
+                        ctl_unit_config->i2c_unit.length);
+
+                    //dump gain mapping
+                    if (ctl_unit_config->i2c_unit.reg_type == REG_FIELD_TYPE_GAIN &&
+                        ctl_unit_config->i2c_unit.reg_value) {
+                        LOGD(dump_path_config4, "\t\t\t|-GainMapping:");
+
+                        APH_VolumeGainMapping *volume_gain_config
+                            = ((APH_GainConfiguration *)ctl_unit_config->i2c_unit.reg_value)->volume_gain_mapping;
+                        while (volume_gain_config) {
+                            LOGD(dump_path_config5, "\t\t\t\t|-[%d 0x%lx]",
+                                volume_gain_config->volume,
+                                volume_gain_config->value);
+                            volume_gain_config = volume_gain_config->next;
+                        }
+                    }
+
+                    //dump coeff values
+                    if (ctl_unit_config->i2c_unit.reg_type == REG_FIELD_TYPE_COEFF &&
+                        ctl_unit_config->i2c_unit.reg_value) {
+                        LOGD(dump_path_config6, "\t\t\t|-Coefficients:");
+
+                        unsigned short i = 0;
+                        for (i = 0; i < ctl_unit_config->i2c_unit.length; i++) {
+                            LOGD(dump_path_config7, "\t\t\t\t|-[0x%lx]", ctl_unit_config->i2c_unit.reg_value[i]);
+                        }
+                    }
+                } else if (component_config->component_ctl_protocol == HCI) {
+                    LOGD(dump_path_config8, "\t\t|-HCIConfig: control_unit=%s ocf=0x%lx ogf=0x%lx length=%d",
+                        _get_ctl_unit_name(ctl_unit_config->control_unit_id, basic_element_table),
+                        ctl_unit_config->hci_unit.hci_ocf,
+                        ctl_unit_config->hci_unit.hci_ogf,
+                        ctl_unit_config->hci_unit.length);
+
+                    //dump HCI parameters
+                    if (ctl_unit_config->hci_unit.length > 0) {
+                        LOGD(dump_path_config9, "\t\t\t|-Parameters:");
+
+                        unsigned short i;
+                        for (i = 0; i < ctl_unit_config->hci_unit.length; i++) {
+                            LOGD(dump_path_config10, "\t\t\t\t|-[0x%lx]", ctl_unit_config->hci_unit.hci_parameters[i]);
+                        }
+                    }
+                } else if (component_config->component_ctl_protocol == GPIO) {
+                    LOGD(dump_path_config11, "\t\t|-GPIOConfig: control_unit=%s gpio_port=%d gpio_value=%d",
+                        _get_ctl_unit_name(ctl_unit_config->control_unit_id, basic_element_table),
+                        ctl_unit_config->gpio_unit.gpio_port,
+                        ctl_unit_config->gpio_unit.gpio_value);
+                }
+
+                ctl_unit_config = ctl_unit_config->next;
+            }
+
+            component_config = component_config->next;
+        }
+
+        path_config = path_config->next;
+    }
+}
+
+void dump_gain_config(APH_GainConfigurationTable *table) {
+    APH_GainConfiguration *gain_config = table->gain_configuration;
+
+    if (!debug_aph_dump_ena)
+        return;
+
+    while (gain_config) {
+        LOGD(dump_gain_config, "GainConfig: path=%s component=%s gain=%s mapping_number=%d",
+            _get_path_identifier(gain_config->path_id, path_config_table),
+            COMPONENT_ENUM2STR(gain_config->component_id),
+            _get_ctl_unit_name(gain_config->gain_id, basic_element_table),
+            gain_config->mapping_number);
+
+        APH_VolumeGainMapping *volume_gain_mapping = gain_config->volume_gain_mapping;
+        while (volume_gain_mapping) {
+            LOGD(dump_gain_config1, "\t|-[%d 0x%lx]", volume_gain_mapping->volume, volume_gain_mapping->value);
+            volume_gain_mapping = volume_gain_mapping->next;
+        }
+
+        gain_config = gain_config->next;
+    }
+}
+
+void dump_coeff_config(APH_CoeffConfigurationTable *table) {
+    APH_CoeffConfiguration *coeff_config = table->coeff_configuration;
+
+    if (!debug_aph_dump_ena)
+        return;
+
+    while (coeff_config) {
+        LOGD(dump_coeff_config, "CoeffConfig: path=%s component=%s operation=%s coeff_group_number=%d",
+            _get_path_identifier(coeff_config->path_id, path_config_table),
+            COMPONENT_ENUM2STR(coeff_config->component_id),
+            OPERATION_ENUM2STR(coeff_config->path_op_id),
+            coeff_config->coeff_group_number);
+        APH_Coefficient_Group *coeff_group = coeff_config->coefficients_group;
+        while (coeff_group)
+        {
+            LOGD(dump_coeff_config1, "CoeffGroupConfig: coeff_id=%s,coeff_value_number=%d",
+                 _get_ctl_unit_name(coeff_group->coeff_id, basic_element_table),
+                 coeff_group->coeff_value_number);
+            APH_Coefficient *coeff = coeff_group->coefficients;
+            while (coeff) {
+                LOGD(dump_coeff_config2, "\t|-[0x%lx]", coeff->value);
+                coeff = coeff->next;
+            }
+
+            coeff_group=coeff_group->next;
+        }
+
+
+        coeff_config = coeff_config->next;
+    }
+
+}
+
+void dump_eqcoeff_config(APH_EQCoeffConfigurationTable *table) {
+    APH_EQCoefficient *eq_coeff_config = table->eq_coeff_configuration;
+
+    LOGD(dump_eqcoeff_config, "EQCoeffConfig: component=%s control_protocol=%s eq_coeff_number=%d",
+        COMPONENT_ENUM2STR(table->component_id),
+        PROTOCOL_ENUM2STR(table->component_ctl_protocol),
+        table->eq_coeff_number);
+
+    if (!debug_aph_dump_ena)
+        return;
+
+        while (eq_coeff_config) {
+            //dump register value
+            if (eq_coeff_config->coeff_filt_addr) {
+                APH_ControlUnitConfiguration *ctl_unit_config = eq_coeff_config->coeff_filt_addr;
+                LOGD(dump_eqcoeff_config1, "\t\t|-RegisterConfig: control_unit=%s reg_index=0x%lx "
+                    "reg_mask=0x%lx reg_shift=0x%lx reg_type=%d length=%d, value=0x%lx",
+                    _get_ctl_unit_name(ctl_unit_config->control_unit_id, basic_element_table),
+                    ctl_unit_config->i2c_unit.reg_index,
+                    ctl_unit_config->i2c_unit.reg_mask,
+                    ctl_unit_config->i2c_unit.reg_shift,
+                    ctl_unit_config->i2c_unit.reg_type,
+                    ctl_unit_config->i2c_unit.length,
+                    *(ctl_unit_config->i2c_unit.reg_value));
+            }
+            //dump eq_coeff
+            if (eq_coeff_config->eq_coeff){
+                APH_ControlUnitConfiguration *ctl_unit_config = eq_coeff_config->eq_coeff;
+                //dump coeff values
+                if (ctl_unit_config->i2c_unit.reg_type == REG_FIELD_TYPE_COEFF &&
+                    ctl_unit_config->i2c_unit.reg_value) {
+                    LOGD(dump_eqcoeff_config2, "\t\t\t|-Coefficients:");
+
+                    unsigned short i = 0;
+                    for (i = 0; i < ctl_unit_config->i2c_unit.length; i++) {
+                        LOGD(dump_eqcoeff_config3, "\t\t\t\t|-[0x%lx]", ctl_unit_config->i2c_unit.reg_value[i]);
+                    }
+                }
+            }
+            //dump eq coeff manager
+            if (eq_coeff_config->coeff_mngr) {
+                APH_ControlUnitConfiguration *ctl_unit_config = eq_coeff_config->coeff_mngr;
+                while(ctl_unit_config){
+                    LOGD(dump_eqcoeff_config4, "\t\t|-RegisterConfig: control_unit=%s reg_index=0x%lx "
+                        "reg_mask=0x%lx reg_shift=0x%lx reg_type=%d length=%d, value=0x%lx",
+                        _get_ctl_unit_name(ctl_unit_config->control_unit_id, basic_element_table),
+                        ctl_unit_config->i2c_unit.reg_index,
+                        ctl_unit_config->i2c_unit.reg_mask,
+                        ctl_unit_config->i2c_unit.reg_shift,
+                        ctl_unit_config->i2c_unit.reg_type,
+                        ctl_unit_config->i2c_unit.length,
+                        *(ctl_unit_config->i2c_unit.reg_value));
+
+                    ctl_unit_config = ctl_unit_config->next;
+                }
+            }
+
+            eq_coeff_config = eq_coeff_config->next;
+        }
+}
+
+void dump_component_ref_count() {
+    int size = sizeof(ACH_component_table) / sizeof(ACH_component_table[0]);
+    int i = 0;
+
+    if (!debug_aph_dump_ena)
+        return;
+
+    for (i = 0; i < size; i++) {
+        LOGD(dump_component_ref_count, "\tComponent[%d]: %s -- %d", i,
+            COMPONENT_ENUM2STR(ACH_component_table[i].component_id),
+            ACH_component_table[i].component_handler->ref_count);
+    }
+}
+
+#endif/*DEBUG_APH_EXTEND_DUMP */
+
+//--------------------------------------------------------------
+//-------- External APH APIs
+//--------------------------------------------------------------
+void ACM_APHInit(void) {
+#ifdef PXA1826_AUDIO
+    int ret = 0;
+    int err, ioctl_fd, status = 0;
+#endif    
+    //load different XML based on Codec and version.
+    char *appendix = NULL;
+    char *audio_basic_element_xml = NULL;
+    char *audio_path_config_xml = NULL;
+    char *audio_gain_config_xml = NULL;
+    char *audio_coeff_config_xml = NULL;
+    appendix = _get_xml_appendix();
+    if (appendix) {
+        GENERATE_XML_NAME(audio_basic_element_xml, XML_NAME_LEN, AUDIO_BASIC_ELEMENT_XML, appendix);
+        if (!audio_basic_element_xml) {
+            free(appendix);
+            return;
+        }
+        GENERATE_XML_NAME(audio_path_config_xml, XML_NAME_LEN, AUDIO_PATH_CONFIG_XML, appendix);
+        if (!audio_path_config_xml) {
+            free(appendix);
+            free(audio_basic_element_xml);
+            return;
+        }
+        GENERATE_XML_NAME(audio_gain_config_xml, XML_NAME_LEN, AUDIO_GAIN_CONFIG_XML, appendix);
+        if (!audio_gain_config_xml) {
+            free(appendix);
+            free(audio_basic_element_xml);
+            free(audio_path_config_xml);
+            return;
+        }
+        GENERATE_XML_NAME(audio_coeff_config_xml, XML_NAME_LEN, AUDIO_COEFF_CONFIG_XML, appendix);
+        if (!audio_coeff_config_xml) {
+            free(appendix);
+            free(audio_basic_element_xml);
+            free(audio_path_config_xml);
+            free(audio_gain_config_xml);
+            return;
+        }
+        LOGI(ACM_APHInit, "%s: used below configure xml files:\n\t%s\n\t%s\n\t%s\n\t%s\n", __FUNCTION__, \
+            audio_basic_element_xml, audio_path_config_xml, audio_gain_config_xml,\
+            audio_coeff_config_xml);
+    }
+
+    //load basic element configuration
+    basic_element_table = parse_basic_elements(audio_basic_element_xml);
+    if (basic_element_table == NULL) {
+        LOGE(ACM_APHInit1, "%s: fail to load basic element table", __FUNCTION__);
+        goto end;
+    }
+
+#ifdef DEBUG_APH
+    LOGD(ACM_APHInit2, "-----Dump Basic Element Table-----");
+    if (basic_element_table)
+        dump_basic_elements(basic_element_table);
+#endif
+
+    //load path configuration
+    path_config_table = parse_path_configuration(audio_path_config_xml, basic_element_table);
+    if (path_config_table == NULL) {
+        LOGE(ACM_APHInit3, "%s: fail to load path configuration table", __FUNCTION__);
+        _free_basic_element_table(basic_element_table);
+        goto end;
+    }
+
+    //load path calibration configuration
+    APH_PathConfigurationTable *path_config_calibration
+        = parse_path_configuration(AUDIO_PATH_CALIBRATION_XML, basic_element_table);
+    if (path_config_calibration) {
+        //update path configuration table
+        _update_path_configuration(path_config_table, path_config_calibration);
+    }
+
+    //initialize path status table and active path table
+    if (_init_path_status_tables(path_config_table->path_number) < 0) {
+        LOGE(ACM_APHInit4, "%s: fail to initialize path status tables", __FUNCTION__);
+        _free_basic_element_table(basic_element_table);
+        _free_path_config_table(path_config_table);
+        goto end;
+    }
+
+    //load gain configuration
+    gain_config_table = parse_gain_configuration(audio_gain_config_xml, basic_element_table, path_config_table);
+
+    //load gain calibration configuration
+    APH_GainConfigurationTable *gain_config_calibration
+        = parse_gain_configuration(AUDIO_GAIN_CALIBRATION_XML, basic_element_table, path_config_table);
+    if (gain_config_table == NULL) {
+        gain_config_table = gain_config_calibration;
+    } else if (gain_config_calibration) {
+        //update gain configuration table
+        _update_gain_configuration(gain_config_table, gain_config_calibration);
+    }
+
+#ifdef DEBUG_APH
+    LOGD(ACM_APHInit5, "-----Dump Gain Config Table-----");
+    if (gain_config_table)
+        dump_gain_config(gain_config_table);
+#endif
+
+    //load coeff configuration
+    coeff_config_table = parse_coeff_configuration(audio_coeff_config_xml, basic_element_table, path_config_table);
+
+    //load coeff calibration configuration
+    APH_CoeffConfigurationTable *coeff_config_calibration
+        = parse_coeff_configuration(AUDIO_COEFF_CALIBRATION_XML, basic_element_table, path_config_table);
+    if (coeff_config_table == NULL) {
+        coeff_config_table = coeff_config_calibration;
+    } else if (coeff_config_calibration) {
+        //update coeff configuration table
+        _update_coeff_configuration(coeff_config_table, coeff_config_calibration);
+    }
+
+#ifdef DEBUG_APH
+    LOGD(ACM_APHInit6, "-----Dump Coeff Config Table-----");
+    if (coeff_config_table)
+        dump_coeff_config(coeff_config_table);
+#endif
+
+    coeff_eqconfig_table = parse_eqcoeff_configuration(audio_coeff_config_xml, basic_element_table);
+#ifdef DEBUG_APH
+    LOGD(ACM_APHInit7, "----Dump EQCoeff config Table-----");
+    if (coeff_config_table)
+        dump_eqcoeff_config(coeff_eqconfig_table);
+#endif
+
+    //attach gain configuration entry to path configuration table
+    _attach_gain_config_to_path(path_config_table, gain_config_table);
+
+    //attach coeff configuration entry to path configuration table
+    _attach_coeff_config_to_path(path_config_table, coeff_config_table);
+
+#ifdef DEBUG_APH
+    LOGD(ACM_APHInit8, "-----Dump Path Config Table-----");
+    if (coeff_config_table)
+        dump_path_config(path_config_table);
+#endif
+
+    //reset components status
+    _reset_components_status();
+    _reset_components_registers();
+
+end:
+
+    /*
+      * 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));
+        goto END_FREE;
+    }
+    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);
+
+    //close the file after got status report
+    close(ioctl_fd);
+#endif
+
+END_FREE:
+    free(appendix);
+    free(audio_basic_element_xml);
+    free(audio_path_config_xml);
+    free(audio_gain_config_xml);
+    free(audio_coeff_config_xml);
+}
+
+void ACM_APHDeInit(void) {
+    if (basic_element_table) _free_basic_element_table(basic_element_table);
+    if (path_config_table) _free_path_config_table(path_config_table);
+    if (gain_config_table) _free_gain_config_table(gain_config_table);
+    if (coeff_config_table) _free_coeff_config_table(coeff_config_table);
+    if (coeff_eqconfig_table) _free_eqcoeff_config_table(coeff_eqconfig_table);
+    if (path_status_table) free(path_status_table);
+    if (active_path_table) free(active_path_table);
+    active_path_number = 0;
+}
+
+ACM_ReturnCode ACM_APHPathHandling(
+    const unsigned char *path,
+    const unsigned char operation,
+    const unsigned char *ref_path,
+    unsigned int value) {
+
+    unsigned short path_id = INVALID_PATH_ID;
+    unsigned short ref_path_id = INVALID_PATH_ID;
+    unsigned char inverse = 0;
+    unsigned char volume = 0;
+    unsigned char final_operation = operation;
+
+    LOGI(ACM_APHPathHandling0, "%s: modem_is_wb=%d, modem_is_master=%d, amixer value=0x%x",
+        __FUNCTION__, modem_is_wb, modem_is_master, value);
+    
+    /*
+      * Set value according to modem_is_wb & modem_is_master
+     */
+#ifdef PXA1826_AUDIO
+    if (1 == modem_is_wb)
+        value |= CODEC_RATE_WB;
+    else
+        value &= ~CODEC_RATE_WB;
+    if (1 == modem_is_master)
+        value |= CODEC_SLAVE;
+    else
+        value &= ~CODEC_SLAVE;
+#endif
+
+    volume = (unsigned char)(value & VOLUME_MASK);
+
+    LOGI(ACM_APHPathHandling, "%s: path=%s operation=%s ref_path=%s amixer value=0x%x",
+        __FUNCTION__, path, OPERATION_ENUM2STR(operation), ref_path, value);
+
+    path_id = _get_path_id(path, path_config_table);
+    if (path_id == INVALID_PATH_ID) {
+        LOGE(ACM_APHPathHandling0, "%s: invalid path identifier", __FUNCTION__);
+        return ACM_RC_INVALID_PATH;
+    }
+
+    if (ref_path) {
+        ref_path_id = _get_path_id(ref_path, path_config_table);
+        if (ref_path_id == INVALID_PATH_ID) {
+            LOGE(ACM_APHPathHandling1, "%s: invalid reference path identifier", __FUNCTION__);
+            return ACM_RC_INVALID_PATH;
+        }
+    }
+
+    //search matched path configuration
+    APH_PathConfiguration *path_config = NULL;
+    APH_PathConfiguration *ref_path_config = NULL;
+    if (ref_path_id == INVALID_PATH_ID) {
+        path_config = _get_path_config(path_id, operation, INVALID_PATH_ID);
+        if (path_config == NULL) {
+            LOGE(ACM_APHPathHandling2, "%s: fail to find path configuration, path=%s op=%s ref_path=%s",
+                __FUNCTION__, path, OPERATION_ENUM2STR(operation), ref_path);
+            return ACM_RC_PATH_CONFIG_NOT_EXIST;
+        }
+    } else {
+        // For "switch" operation
+        if ((!_is_path_active(ref_path_id)) && (!_is_path_active(path_id))) {
+            // For case ref path and path are both not active
+            final_operation = ENABLE;
+            path_config = _get_path_config(path_id, final_operation, INVALID_PATH_ID);
+            if (path_config == NULL) {
+                LOGE(ACM_APHPathHandling3, "%s: fail to find path %s for switch operation", __FUNCTION__, path);
+                return ACM_RC_PATH_CONFIG_NOT_EXIST;
+            }
+        } else if (_is_path_active(ref_path_id) && _is_path_active(path_id)) {
+            // For case ref path and path are both active
+            if (ref_path_id == path_id)
+                return ACM_RC_PATH_ALREADY_ENABLED;
+            final_operation = DISABLE;
+            ref_path_config = _get_path_config(ref_path_id, final_operation, INVALID_PATH_ID);
+            if (ref_path_config == NULL) {
+                LOGE(ACM_APHPathHandling4, "%s: fail to find ref path %s for switch operation", __FUNCTION__, ref_path);
+                return ACM_RC_PATH_CONFIG_NOT_EXIST;
+            }
+        } else if (_is_path_active(ref_path_id) && (!_is_path_active(path_id))) {
+            // For case ref path is active and path is not active
+            path_config = _get_path_config(path_id, ENABLE, INVALID_PATH_ID);
+            ref_path_config = _get_path_config(ref_path_id, DISABLE, INVALID_PATH_ID);
+            if (path_config == NULL || ref_path_config == NULL) {
+                LOGE(ACM_APHPathHandling5, "%s: fail to find path %s or ref path %s for switch operation", __FUNCTION__, path, ref_path);
+                return ACM_RC_PATH_CONFIG_NOT_EXIST;
+            }
+        } else {
+            LOGE(ACM_APHPathHandling6, "%s: path is alrealy exist, path=%s op=%s ref_path=%s",
+                __FUNCTION__, path, OPERATION_ENUM2STR(operation), ref_path);
+            return ACM_RC_PATH_ALREADY_ENABLED;
+        }
+    }
+
+    //update status according to specific operation
+    switch (final_operation) {
+    case ENABLE:
+        if (!ref_path && _is_path_active(path_id) && !_is_path_config_changed(path_id, value))
+            return ACM_RC_PATH_ALREADY_ENABLED;
+        //update path status table and active path table
+        _add_active_path(path_id, value);
+        break;
+    case DISABLE:
+        if (!_is_path_active(path_id)) return ACM_RC_PATH_ALREADY_DISABLED;
+        //update path status table and active path table
+        _remove_active_path(path_id);
+        break;
+    case MUTE:
+        if (!_is_path_active(path_id)) return ACM_RC_PATH_NOT_ENABLED;
+        if (_is_path_muted(path_id) == volume) return ACM_RC_NO_MUTE_CHANGE_NEEDED;
+        path_status_table[path_id - 1].mute = volume;
+        //inverse register value for unmute operation
+        if (volume == 0) {
+            inverse = 1;
+        }
+        break;
+    case SETVOLUME:
+        if (!_is_path_active(path_id)) return ACM_RC_PATH_NOT_ENABLED;
+        if (volume > MAX_VOLUME_INDEX) return ACM_RC_INVALID_VOLUME_CHANGE;
+        path_status_table[path_id - 1].value = value;
+        break;
+    case SWITCH:
+        //update path status table and active path table
+        _remove_active_path(ref_path_id);
+        _add_active_path(path_id, value);
+        break;
+    default:
+        break;
+    }
+
+    _update_ref_count(path_id, ref_path_id, final_operation, value);
+#ifdef DEBUG_APH
+    if (operation == ENABLE || operation == DISABLE)
+        dump_basic_elements_with_positive_ref_cnt(basic_element_table);
+#endif
+
+    //first enable path, set the eq coefficiency
+    if ((active_path_number == 1 && operation == ENABLE && coeff_eqconfig_table)){
+        _set_eq_coefficiency(coeff_eqconfig_table);
+    }
+
+    //configure path according found configuration
+    if (operation == SWITCH) {
+        if (final_operation == SWITCH) {
+            _set_path_configuration(ref_path, ref_path_config, DISABLE, value, inverse, 0);
+            _set_path_configuration(path, path_config, ENABLE, value, inverse, 1);
+        } else if (final_operation == ENABLE) {
+            _set_path_configuration(path, path_config, final_operation, value, inverse, 0);
+        } else if (final_operation == DISABLE) {
+            _set_path_configuration(ref_path, ref_path_config, final_operation, value, inverse, 0);
+        }
+    } else {
+        _set_path_configuration(path, path_config, final_operation, value, inverse, 0);
+    }
+
+    if(operation != MUTE && operation != DISABLE)
+        path_status_table[path_id - 1].value = value;
+
+    //turn off component if it's not in use
+    _turn_off_standby_components();
+
+    return ACM_RC_OK;
+}
+
+const APH_BasicElementsTable *ACM_GetBasicElementTable() {
+    return basic_element_table;
+}
+
+const APH_PathConfigurationTable *ACM_GetPathConfigTable() {
+    return path_config_table ;
+}
+
+const  APH_GainConfigurationTable *ACM_GetGainConfigTable() {
+    return gain_config_table;
+}
+
+const APH_CoeffConfigurationTable *ACM_GetCoeffConfigTable() {
+    return coeff_config_table;
+}
+
+const APH_PathStatus *ACM_GetPathStatusTable() {
+    return path_status_table;
+}
+
+int ACM_IsPathActive(unsigned short path_id) {
+    return _is_path_active(path_id);
+}
+
+int ACM_IsVoicePathActive() {
+    return _is_voice_path_active();
+}
+
+const unsigned char *ACM_GetPathIdentifier(unsigned short path_id) {
+    return _get_path_identifier(path_id, path_config_table);
+}
+
+const char *ACM_GetXmlAppendix() {
+    return _get_xml_appendix();
+}
+
+unsigned short ACM_GetControlUnitId(const unsigned char *name, const APH_BasicElementsTable *basic_info) {
+    return _get_ctl_unit_id(name, basic_info);
+}
+
+ACM_ReturnCode ACM_GetPathDirection(const unsigned char *path_identifier, unsigned char *path_direction) {
+    return _get_path_direction(path_identifier, path_direction);
+}
+
+void ACM_TurnOffAllComponents() {
+    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->ACH_Disable();
+        ACH_component_table[i].component_handler->active = COMPONENT_INACTIVE;
+    }
+}
+
+ACM_ReturnCode ACM_APHGetMSAGain(const unsigned char *path_name, unsigned char *volume, unsigned short ctr_unit_id, signed char *gain) {
+    ACM_ReturnCode acmReturnCode = ACM_RC_INVALID_PARAMETER;
+    unsigned char *gain_value = NULL;
+    unsigned char path_id = _get_path_id(path_name, path_config_table);
+    APH_GainConfiguration *gain_config = _get_gain_config(path_id, MODEM, ctr_unit_id, gain_config_table);
+
+    if(gain_config != NULL) {
+        gain_value = _get_gain_value(gain_config, volume);
+        if (gain_value) {
+            *gain = *gain_value - DIGITAL_GAIN_MAPPING;
+            acmReturnCode = ACM_RC_OK;
+        }
+    } else {
+        LOGE(ACM_APHGetMSAGain, "%s: ERROR: can not find the matched gain config", __FUNCTION__);
+    }
+
+    return acmReturnCode;
+}
+
+APH_PathType ACM_APHGetPathType(unsigned short path_id) {
+
+    const unsigned char *path_identifier = _get_path_identifier(path_id, path_config_table);
+    APH_PathType path_type = UNKNOW_PATH;
+    if (path_identifier == NULL)
+        return UNKNOW_PATH;
+    if(strstr((char *)path_identifier, "Voice") != NULL) {
+        path_type = VOICE_PATH;
+    }
+    if(strstr((char *)path_identifier, "HiFi") != NULL) {
+        path_type = HIFI_PATH;
+    }
+    if(strstr((char *)path_identifier, "FM") != NULL) {
+        path_type = FM_PATH;
+    }
+    return path_type;
+}
+
+/* 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("%s not found. Create with default value %s", PROPERTY_AUDIO_CODEC, "1");*/
+		property_set(PROPERTY_AUDIO_CODEC, property_value, "1");
+	}
+}
diff --git a/marvell/services/audio/libacm/acm/src/acm_api.c b/marvell/services/audio/libacm/acm/src/acm_api.c
new file mode 100644
index 0000000..3019eab
--- /dev/null
+++ b/marvell/services/audio/libacm/acm/src/acm_api.c
@@ -0,0 +1,173 @@
+/*
+* 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_api"
+#define LOG_NDEBUG 0
+
+#include <cutils/log.h>
+#include "acm_api.h"
+#include "acm_aph.h"
+#include "acm_param.h"
+
+#ifdef WITH_AUDIO_CALIBRATION
+#include "ac_thread.h"
+#endif
+
+#ifdef TARGET_mmp_asr1901_KSTR901
+#include "audio_dsp.h"
+extern void ACM_SendVEtoADSP(void);
+#endif
+
+static unsigned int msa_gain_mode = MSA_GAIN_NORMAL_MODE;
+
+void ACMInit(void) {
+    ACM_APHInit();
+    ACM_Init_Property();    // property depends on modem_is_master inited ACM_APHInit()
+#ifdef WITH_AUDIO_CALIBRATION
+    ACM_Init_Calibration_IPC();
+#endif
+
+#if defined(CODEC_ALC5616)
+    ACM_enable_headset_detection_ALC5616();
+#endif
+
+    audio_pa_init();
+
+#ifdef TARGET_mmp_asr1901_KSTR901
+    audio_dsp_init();
+    ACM_SendVEtoADSP();
+#endif
+}
+
+void ACMDeInit(void) {
+#ifdef WITH_AUDIO_CALIBRATION
+    ACM_Cancel_Calibration_IPC();
+#endif
+}
+
+extern APH_PathStatus path_status_table[APH_PATH_ID_CNT];
+audio_mode_t ACMGetAudioMode(void)
+{
+    if (((path_status_table[APH_PATH_ID_HIFIPLAYTOEARPHONE].enabled) ||(path_status_table[APH_PATH_ID_HIFIPLAYTOSPKR].enabled))
+        && (path_status_table[APH_PATH_ID_HIFIRECORDFROMMIC1].enabled))
+    {
+        return AUDIO_MODE_NORMAL;
+    }
+    else if ((path_status_table[APH_PATH_ID_HIFIPLAYTOHP].enabled) && (path_status_table[APH_PATH_ID_HIFIRECORDFROMHSMIC].enabled))
+    {
+        return AUDIO_MODE_NORMAL;
+    }
+    else if (((path_status_table[APH_PATH_ID_VOICEPLAYTOEARPHONE].enabled) ||(path_status_table[APH_PATH_ID_VOICEPLAYTOSPKR].enabled)
+                  || (path_status_table[APH_PATH_ID_VOICEPLAYTOHP].enabled ))
+        && (path_status_table[APH_PATH_ID_VOICERECORDFROMMIC1].enabled))
+    {
+        return AUDIO_MODE_IN_CALL;
+    }
+    else if ((path_status_table[APH_PATH_ID_VOICEPLAYTOHP].enabled ) && (path_status_table[APH_PATH_ID_VOICERECORDFROMHSMIC].enabled))
+    {
+        return AUDIO_MODE_IN_CALL;
+    }
+    else
+    {
+        return AUDIO_MODE_INVALID;
+    }
+
+}
+
+ACM_ReturnCode ACMAudioPathEnable(const char * path, unsigned int value) {
+    ACM_ReturnCode rc = ACM_RC_INVALID_PATH;
+    rc = APHAudioPathEnable(path,value);
+
+    if( rc == ACM_RC_OK )
+        APHAudioPathVolumeSet(path, value);
+
+    return rc;
+}
+
+ACM_ReturnCode ACMAudioPathDisable(const char * path) {
+    return APHAudioPathDisable(path);
+}
+
+ACM_ReturnCode ACMAudioPathSwitch (const char * path_Rx, const char * path_Tx, unsigned int value) {
+    return APHAudioPathSwitch (path_Rx, path_Tx, value);
+}
+
+ACM_ReturnCode ACMAudioPathMute(const char * path, unsigned int value) {
+    return APHAudioPathMute(path, value > 0 ? 1: 0);
+}
+
+ACM_ReturnCode ACMAudioPathVolumeSet(const char * path, unsigned int value) {
+    return APHAudioPathVolumeSet(path, value);
+}
+
+ACM_ReturnCode ACMGetPathStatus(char * buff, unsigned int MaxSize) {
+    return ACM_GetPathStatus(buff, MaxSize);
+}
+
+ACM_ReturnCode ACMGetParameter(unsigned int param_id, void *param, unsigned int *size) {
+    UNUSEDPARAM(size);
+
+    ACM_ReturnCode acmReturnCode = ACM_RC_INVALID_PARAMETER;
+    signed short gain;
+    signed short sidetone_gain = 0;
+    ACM_MsaGain *msa_gain = (ACM_MsaGain *)param;
+    unsigned char volume = 0;
+
+    LOGI(ACMGetParameter, "%s/L%d: param_id=%d, volume=0x%x", __FUNCTION__, __LINE__, param_id, msa_gain->volume);
+
+    switch(param_id) {
+        case ACM_MSA_GAIN:
+            //volume range: 0,10,20,...,100
+            volume = (msa_gain->volume + 5) /10;
+            volume = volume *10;
+            if(volume > 100)
+                volume = 100;
+
+            if(APHGetMSAGain(msa_gain->out_path_name, msa_gain->path_name, &volume, APH_GAIN_ID_NB, &gain, &sidetone_gain)==ACM_RC_OK) {
+                msa_gain->gain = gain & 0xff;
+                msa_gain->wbGain = (gain >> 8) & 0xff;
+                msa_gain->sidetone_gain = sidetone_gain & 0xff;
+                msa_gain->sidetone_wbGain = (sidetone_gain >> 8) & 0xff;
+                msa_gain->volume = volume;
+                acmReturnCode = ACM_GetPathDirection(msa_gain->path_name, &(msa_gain->path_direction));
+             }
+            return acmReturnCode;
+        default:
+            return ACM_RC_INVALID_PARAMETER;
+    }
+    return ACM_RC_OK;
+}
+
+ACM_ReturnCode ACMSetParameter(unsigned int param_id, void *param, unsigned int value) {
+    UNUSEDPARAM(param);
+
+    switch(param_id) {
+        case ACM_MSA_GAIN_MODE:
+            msa_gain_mode = value;
+            break;
+        default:
+            return ACM_RC_INVALID_PARAMETER;
+    }
+    return ACM_RC_OK;
+}
+
diff --git a/marvell/services/audio/libacm/acm/src/acm_api_old.c b/marvell/services/audio/libacm/acm/src/acm_api_old.c
new file mode 100644
index 0000000..1e6c62b
--- /dev/null
+++ b/marvell/services/audio/libacm/acm/src/acm_api_old.c
@@ -0,0 +1,111 @@
+/*
+* 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_api"
+#define LOG_NDEBUG 0
+
+#include <cutils/log.h>
+#include "acm_api.h"
+#include "acm_aph.h"
+#include "acm_param.h"
+
+#ifdef WITH_AUDIO_CALIBRATION
+#include "ac_thread.h"
+#endif
+static unsigned int msa_gain_mode = MSA_GAIN_NORMAL_MODE;
+
+void ACMInit(void) {
+    ACM_Init_Property();
+    ACM_APHInit();
+#ifdef WITH_AUDIO_CALIBRATION
+    ACM_Init_Calibration_IPC();
+#endif
+}
+
+void ACMDeInit(void) {
+    ACM_APHDeInit();
+}
+
+ACM_ReturnCode ACMAudioPathEnable(const char * path, unsigned int value) {
+    return ACM_APHPathHandling((const unsigned char *)path, ENABLE, NULL, value);
+}
+
+ACM_ReturnCode ACMAudioPathDisable(const char * path) {
+    return ACM_APHPathHandling((const unsigned char *)path, DISABLE, NULL, 0);
+}
+
+ACM_ReturnCode ACMAudioPathSwitch (const char * path_old, const char * path_new, unsigned int value) {
+    return ACM_APHPathHandling((const unsigned char *)path_new, SWITCH, (const unsigned char *)path_old, value);
+}
+
+ACM_ReturnCode ACMAudioPathMute(const char * path, unsigned int value) {
+    return ACM_APHPathHandling((const unsigned char *)path, MUTE, NULL, value);
+}
+
+ACM_ReturnCode ACMAudioPathVolumeSet(const char * path, unsigned int value) {
+    return ACM_APHPathHandling((const unsigned char *)path, SETVOLUME, NULL, value);
+}
+
+ACM_ReturnCode ACMGetParameter(unsigned int param_id, void *param, unsigned int *size) {
+    ACM_ReturnCode acmReturnCode = ACM_RC_INVALID_PARAMETER;
+    const APH_BasicElementsTable *basic_element_table = ACM_GetBasicElementTable();
+    unsigned short ctr_unit_id, ctr_unit_id_extra, ctr_unit_id_wb, ctr_unit_id_extra_wb;
+    signed char gain, gain_wb, gain_extra, gain_extra_wb;
+    ACM_MsaGain *msa_gain = (ACM_MsaGain *)param;
+
+    switch(param_id) {
+        case ACM_MSA_GAIN:
+            ctr_unit_id = ACM_GetControlUnitId((const unsigned char*)"DIGITAL_GAIN_NB", basic_element_table);
+            ctr_unit_id_extra = ACM_GetControlUnitId((const unsigned char*)"DIGITAL_GAIN_EXTRA", basic_element_table);
+            ctr_unit_id_wb = ACM_GetControlUnitId((const unsigned char*)"DIGITAL_GAIN_WB", basic_element_table);
+            ctr_unit_id_extra_wb = ACM_GetControlUnitId((const unsigned char*)"DIGITAL_GAIN_EXTRA_WB", basic_element_table);
+            if(ACM_APHGetMSAGain(msa_gain->path_name, &msa_gain->volume, ctr_unit_id, &gain)==ACM_RC_OK) {
+                ACM_APHGetMSAGain(msa_gain->path_name, &msa_gain->volume, ctr_unit_id_extra, &gain_extra);
+                ACM_APHGetMSAGain(msa_gain->path_name, &msa_gain->volume, ctr_unit_id_wb, &gain_wb);
+                ACM_APHGetMSAGain(msa_gain->path_name, &msa_gain->volume, ctr_unit_id_extra_wb, &gain_extra_wb);
+                if(msa_gain_mode) {
+                    msa_gain->gain = gain_extra;
+                    msa_gain->wbGain = gain_extra_wb;
+                } else {
+                    msa_gain->gain = gain;
+                    msa_gain->wbGain = gain_wb;
+                }
+                acmReturnCode = ACM_GetPathDirection(msa_gain->path_name, &(msa_gain->path_direction));
+            }
+            return acmReturnCode;
+        default:
+            return ACM_RC_INVALID_PARAMETER;
+    }
+    return ACM_RC_OK;
+}
+
+ACM_ReturnCode ACMSetParameter(unsigned int param_id, void *param, unsigned int value) {
+    switch(param_id) {
+        case ACM_MSA_GAIN_MODE:
+            msa_gain_mode = value;
+            break;
+        default:
+            return ACM_RC_INVALID_PARAMETER;
+    }
+    return ACM_RC_OK;
+}
diff --git a/marvell/services/audio/libacm/acm/src/acm_elba.c b/marvell/services/audio/libacm/acm/src/acm_elba.c
new file mode 100644
index 0000000..9290954
--- /dev/null
+++ b/marvell/services/audio/libacm/acm/src/acm_elba.c
@@ -0,0 +1,310 @@
+/*
+* 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_ach_elba"
+#define LOG_NDEBUG 0
+
+#include <cutils/log.h>
+#include "acm_elba.h"
+
+int codec_reg_num = NUM_OF_REGS;
+
+static void Elba_Enable(void);
+static void Elba_Disable(void);
+static void Elba_Reset(void);
+static void Elba_GetTypeAndID(int *type, unsigned char *id);
+static ACH_ReturnCode Elba_Handle(void *setting);
+
+ACH_ComponentHandler elba_handler = {
+    COMPONENT_INACTIVE,
+    0,
+    Elba_Enable,
+    Elba_Disable,
+    Elba_Reset,
+    Elba_GetTypeAndID,
+    Elba_Handle,
+};
+
+extern int I2CInit(void);
+extern int I2CDeInit(void);
+extern void I2CWrite(unsigned char numid, unsigned short value);
+extern void I2CBurstWrite(unsigned char numid, unsigned char size, unsigned char *value);
+extern void I2CRead(unsigned char numid, unsigned char *value);
+extern void I2CBurstRead(unsigned char numid, unsigned char *value, int size, int offset);
+
+#ifdef PXA1826_AUDIO
+#ifndef ACM_ALSA_INIT
+#define ACM_ALSA_INIT
+#endif
+#endif
+
+#ifdef DEBUG_FAKE_ACH
+#undef ACM_ALSA_INIT
+#endif
+
+
+static void Elba_RegSet(unsigned char numid, unsigned short value) {
+#ifndef DEBUG_FAKE_ACH
+    I2CWrite(numid, value);
+#else
+	LOGD(Elba_RegSet, "  FAKE_ACH: %s(0x%x, 0x%x)", __FUNCTION__, numid, value);
+#endif
+}
+
+static void Elba_RegBurstSet(unsigned char numid, unsigned char size, unsigned char *value) {
+#ifndef DEBUG_FAKE_ACH
+    I2CBurstWrite(numid, size, value);
+#else
+	LOGD(Elba_RegBurstSet, "  FAKE_ACH: %s(0x%x, 0x%x, ..)", __FUNCTION__, numid, size);
+#endif
+}
+
+void Elba_RegGet(unsigned char numid, unsigned char *value) {
+#ifndef DEBUG_FAKE_ACH
+    I2CRead(numid, value);
+#else
+	LOGD(Elba_RegGet, "  FAKE_ACH: %s(0x%x, ..)", __FUNCTION__, numid);
+#endif
+}
+
+void Elba_RegBurstGet(unsigned char numid, unsigned char *value, int size, int offset) {
+#ifndef DEBUG_FAKE_ACH
+    I2CBurstRead(numid, value, size, offset);
+#else
+	LOGD(Elba_RegBurstGet, "  FAKE_ACH: %s(0x%x, .., 0x%x, 0x%x)", __FUNCTION__, numid, size, offset);
+#endif
+}
+
+static void Elba_ResetRegCache() {
+    int size = sizeof(reg_cache) / sizeof(reg_cache[0]);
+    int i = 0;
+
+    for (i = 0; i < size; i++) {
+        reg_cache[i].reg_value = reg_cache[i].reg_default;
+    }
+}
+
+unsigned char Elba_GetRegNumId(unsigned char reg_index) {
+    unsigned char i = 0;
+
+    for (i = 0; i < NUM_OF_REGS; i++) {
+        if (reg_cache[i].reg_index == reg_index) {
+            return REG_NUMID_BASE + i;
+        }
+    }
+
+    return 0;
+}
+
+//--------------------------------------------------------------
+//-------- External ACH APIs
+//--------------------------------------------------------------
+#ifdef ACM_ALSA_INIT
+// NOTE about pair Enable/Disable
+//  On startup Disable could be called without Enable as Init/Reset sequence
+//  Let's "force" I2CInit() for first only Disable without Enable
+//
+static int _acm_initialized = 0;
+#endif
+
+static void Elba_Enable(void) {
+    LOGI(Elba_Enable, "%s: enable elba component", __FUNCTION__);
+
+    unsigned char elba_pu = 0;
+    unsigned int elba_max_boot_count = 100;
+
+#ifdef ACM_ALSA_INIT
+    LOGI(Elba_Enable, "%s: _acm_initialized=%d!", __FUNCTION__, _acm_initialized);
+	_acm_initialized = 1;
+	I2CInit(); //adaptor to alsa-mixer
+#endif
+    reg_cache[ELBA_MAIN_POWERUP_ID].reg_value = 0x03;
+    Elba_RegSet(ELBA_MAIN_POWERUP_ID, 0x03);
+    Elba_RegGet(ELBA_AUTO_SEQUENCE_STS_1, &elba_pu);
+    while (!(elba_pu & (1 << ELBA_SEQ_PU_READY)) && elba_max_boot_count) {
+        usleep(1000);
+        Elba_RegGet(ELBA_AUTO_SEQUENCE_STS_1, &elba_pu);
+        elba_max_boot_count--;
+    }
+
+    if (!elba_max_boot_count) {
+        LOGE(Elba_Enable1, "%s: power up elba failed", __FUNCTION__);
+    } else {
+        // Disable HP short autorecovery.
+        // Register 0x0A = 0x02.
+        reg_cache[ELBA_HP_SHRT_AR_ID].reg_value = 0x02;
+        Elba_RegSet(ELBA_HP_SHRT_AR_ID, 0x02);
+    }
+}
+
+static void Elba_Disable(void) {
+    LOGI(Elba_Disable, "%s: disable elba component", __FUNCTION__);
+
+#ifdef ACM_ALSA_INIT
+	if (!_acm_initialized) {
+		_acm_initialized = 1;
+		I2CInit(); //adaptor to alsa-mixer
+	}
+#endif
+    reg_cache[ELBA_MAIN_POWERUP_ID].reg_value = 0;
+    Elba_RegSet(ELBA_MAIN_POWERUP_ID, 0);
+    usleep(2000);
+#ifdef ACM_ALSA_INIT
+	I2CDeInit(); //adaptor to alsa-mixer
+#endif
+}
+
+static void Elba_Reset(void) {
+    LOGI(Elba_Reset, "%s: Reset elba registers!", __FUNCTION__);
+    int size = sizeof(reg_cache) / sizeof(reg_cache[0]);
+    int size_col = sizeof(reg_cache[0]) / sizeof(unsigned char);
+    int i, k = 0;
+    unsigned char j, numid, value, cache_idx;
+    Elba_RegisterCache reg_cache_inorder[size];
+
+#ifdef ACM_ALSA_INIT
+	I2CInit(); //make sure to enable mixer before and close after this operation
+#endif
+    for (j = 0x0; j <= 0xff; j++){
+        if (k == size){
+            LOGI(Elba_Reset1, "%s: copy completed !", __FUNCTION__);
+            break;
+        }
+
+        for (i = 0; i < size; i++) {
+            if (reg_cache[i].reg_prior == j) {
+                memcpy(&reg_cache_inorder[k], &reg_cache[i], size_col);
+                k++;
+            }
+        }
+    }
+
+    for (k = 0; k < size; k++) {
+        if (reg_cache_inorder[k].reg_prior == 0x0) {
+            continue;
+        } else {
+            break;
+        }
+    }
+
+    for (; k < size; k++) {
+        numid = Elba_GetRegNumId(reg_cache_inorder[k].reg_index);
+        if (numid == 0 || numid == ELBA_COEFF_ID) {
+            LOGW(Elba_Reset2, "%s: Invalid or useless numid = %d!", __FUNCTION__, numid);
+            continue;
+        }
+
+        if (numid == ELBA_MAIN_POWERUP_ID) {
+            value = 0x03;
+        } else {
+            value = reg_cache_inorder[k].reg_default;
+        }
+
+        cache_idx = numid - REG_NUMID_BASE;
+        if (cache_idx < size)
+            reg_cache[cache_idx].reg_value = value;
+        Elba_RegSet(numid, value);
+#ifdef DEBUG_ELBA
+        LOGI(Elba_Reset3, "%s: resets elba register 0x%lx to value --> 0x%lx",
+            __FUNCTION__,
+            reg_cache_inorder[k].reg_index,
+            value);
+#endif
+    }
+
+    Elba_RegSet(ELBA_MAIN_POWERUP_ID, 0x00);
+#ifdef ACM_ALSA_INIT
+	I2CDeInit(); //make sure to enable mixer before and close after this operation
+#endif
+}
+
+static void Elba_GetTypeAndID(int *type, unsigned char *id) {
+#ifdef ACM_ALSA_INIT
+	I2CInit(); //make sure to enable mixer before and close after this operation
+#endif
+    LOGI(Elba_GetTypeAndID, "%s: Get type and ID for elba component", __FUNCTION__);
+    *type = COMPONENT_TYPE_CODEC;
+    Elba_RegGet(ELBA_ID_REG, id);
+#ifdef ACM_ALSA_INIT
+	I2CDeInit(); //make sure to enable mixer before and close after this operation
+#endif
+}
+
+static ACH_ReturnCode Elba_Handle(void *setting) {
+    ACH_ComponentParameter *param = (ACH_ComponentParameter *)setting;
+    unsigned short i = 0;
+    unsigned short numid, value, cache_idx;
+
+    if (param && param->i2c.reg_value) {
+        numid = Elba_GetRegNumId(param->i2c.reg_index);
+
+        LOGI(Elba_Handle, "%s: REG_NUMID_BASE=%d, numid=%d. set register 0x%lx values:0x%lx ",
+                    __FUNCTION__, REG_NUMID_BASE, numid, param->i2c.reg_index,  *(param->i2c.reg_value));
+
+        if (numid > 0) {
+            if (param->i2c.length == 2) {
+                //compare with register cache
+                cache_idx = numid - REG_NUMID_BASE;
+                value = (reg_cache[cache_idx].reg_value & ~param->i2c.reg_mask) | (*param->i2c.reg_value);
+
+                if (((reg_cache[cache_idx].reg_value & param->i2c.reg_mask) != (*param->i2c.reg_value)) ||
+                    // For HP short start reset
+                    ((reg_cache[cache_idx].reg_index) == 0x28))
+                {
+#ifdef DEBUG_ELBA
+                    LOGI(Elba_Handle, "%s: cache_idx=%d, numid=%d. set register 0x%lx [0x%lx --> 0x%lx]",
+                        __FUNCTION__,
+                        cache_idx,
+                        numid,
+                        param->i2c.reg_index,
+                        reg_cache[cache_idx].reg_value,
+                        value);
+#endif
+                    reg_cache[cache_idx].reg_value = value;
+                    //Elba_RegSet(numid, reg_cache[cache_idx].reg_value);
+                    Elba_RegSet(numid, value);
+                } else {
+#ifdef DEBUG_ELBA
+                    LOGI(Elba_Handle1, "%s: set register 0x%lx [0x%lx --> 0x%lx] (unchanged)",
+                        __FUNCTION__,
+                        param->i2c.reg_index,
+                        reg_cache[cache_idx].reg_value,
+                        reg_cache[cache_idx].reg_value);
+#endif
+                }
+            } else if (param->i2c.length > 2) {
+                //FIXME current no register cache is provided for mixer/eq configuration
+#ifdef DEBUG_ELBA
+                LOGI(Elba_Handle2, "%s: numid=%d. set register 0x%lx values:", __FUNCTION__, numid, param->i2c.reg_index);
+                for (i = 0; i < param->i2c.length; i++) {
+                    LOGI(Elba_Handle3, "%s: \t\t\t    -->0x%lx", __FUNCTION__, param->i2c.reg_value[i]);
+                }
+#endif
+
+                Elba_RegBurstSet(numid, param->i2c.length, param->i2c.reg_value);
+            }
+        }
+    }
+
+    return ACH_RC_OK;
+}
diff --git a/marvell/services/audio/libacm/acm/src/acm_gelato.c b/marvell/services/audio/libacm/acm/src/acm_gelato.c
new file mode 100644
index 0000000..9937916
--- /dev/null
+++ b/marvell/services/audio/libacm/acm/src/acm_gelato.c
@@ -0,0 +1,217 @@
+/*
+* 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_ach_gelato"
+#define LOG_NDEBUG 0
+
+#define SYSCLK_DEV "/proc/driver/sspa_sysclk"
+
+#include <cutils/log.h>
+#include "acm_gelato.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+int codec_reg_num = NUM_OF_REGS;
+
+static void CODEC_Enable(void);
+static void CODEC_Disable(void);
+static void CODEC_Reset(void);
+static void CODEC_GetTypeAndID(int *type, unsigned char *id);
+static ACH_ReturnCode CODEC_Handle(void *setting);
+
+ACH_ComponentHandler CODEC_handler = {
+    COMPONENT_INACTIVE,
+    0,
+    CODEC_Enable,
+    CODEC_Disable,
+    CODEC_Reset,
+    CODEC_GetTypeAndID,
+    CODEC_Handle,
+};
+
+extern void I2CWrite(unsigned char numid, unsigned short value);
+extern void I2CBurstWrite(unsigned char numid, unsigned char size, unsigned char *value);
+extern void I2CRead(unsigned char numid, unsigned char *value);
+extern void I2CBurstRead(unsigned char numid, unsigned char *value, unsigned char *size);
+
+static void CODEC_RegSet(unsigned char numid, unsigned char value) {
+#ifndef DEBUG_FAKE_ACH
+    I2CWrite(numid, value);
+#endif
+}
+
+static void CODEC_RegBurstSet(unsigned char numid, unsigned char size, unsigned char *value) {
+#ifndef DEBUG_FAKE_ACH
+    I2CBurstWrite(numid, size, value);
+#endif
+}
+
+void CODEC_RegGet(unsigned char numid, unsigned char *value) {
+#ifndef DEBUG_FAKE_ACH
+    I2CRead(numid, value);
+#endif
+}
+
+void CODEC_RegBurstGet(unsigned char numid, unsigned char *value, unsigned char *size) {
+#ifndef DEBUG_FAKE_ACH
+    I2CBurstRead(numid, value, size);
+#endif
+}
+
+static void CODEC_ResetRegCache() {
+    int size = sizeof(reg_cache) / sizeof(reg_cache[0]);
+    int i = 0;
+
+    for (i = 0; i < size; i++) {
+        reg_cache[i].reg_value = reg_cache[i].reg_default;
+    }
+}
+
+unsigned char CODEC_GetRegNumId(unsigned char reg_index) {
+    unsigned char i = 0;
+
+    for (i = 0; i < NUM_OF_REGS; i++) {
+        if (reg_cache[i].reg_index == reg_index) {
+            return REG_NUMID_BASE + i;
+        }
+    }
+
+    return 0;
+}
+
+//--------------------------------------------------------------
+//-------- External ACH APIs
+//--------------------------------------------------------------
+static void CODEC_Enable(void) {
+    int mDev;
+    LOGI(CODEC_Enable, "%s: enable gelato component", __FUNCTION__);
+
+    /* Open sysclk */
+    mDev = open(SYSCLK_DEV, O_RDWR);
+    if (mDev < 0) {
+        LOGE(CODEC_Enable1, "%s: Failed to open %s\n", __FUNCTION__, SYSCLK_DEV);
+    } else {
+        write(mDev, "1", 1);
+        mDev = -1;
+        LOGI(CODEC_Enable2, "%s: open sysclk\n", __FUNCTION__);
+    }
+
+    /* To be implemented after power control regiter is supported in GELATO production version */
+    //usleep(2000);
+    CODEC_RegSet(0x11, 0x00);
+    CODEC_RegSet(0x11, 0x01);
+    CODEC_ResetRegCache();
+
+    CODEC_RegSet(0xc8, 0x01);
+    CODEC_RegSet(0x25, 0x00);
+    CODEC_RegSet(0xd4, 0xff);
+    reg_cache[0xc8].reg_value = 0x01;
+    reg_cache[0x25].reg_value = 0x00;
+    reg_cache[0xd4].reg_value = 0xff;
+}
+
+static void CODEC_Disable(void) {
+    int mDev;
+    LOGI(CODEC_Disable, "%s: disable gelato component", __FUNCTION__);
+
+    /* disable sysclk */
+    mDev = open(SYSCLK_DEV, O_RDWR);
+    if (mDev < 0) {
+        LOGE(CODEC_Disable1, "%s: Failed to open %s\n", __FUNCTION__, SYSCLK_DEV);
+    } else {
+    /* now there's a work around, as EDEN Z1 use gelato to do HS detection, we cannot shut down its work clock, otherwise HS detection function will not work */
+        //write(mDev, "0", 1);
+        mDev = -1;
+        LOGI(CODEC_Disable2, "%s: disable sysclk\n", __FUNCTION__);
+    }
+
+    /* To be implemented after power control regiter is supported in GELATO production version */
+    //usleep(2000);
+
+    /* Should power down codec to save power here, but R26.3 GELATO cannot dectect plugged-in headset before power up, so we cannot disable codec now even at idle state, will refine this after GELATO improved its headset detection function */
+    //CODEC_RegSet(0x11, 0x31);
+    //reg_cache[0xc8].reg_value = 0x31;
+}
+
+static void CODEC_Reset(void) {
+    LOGI(CODEC_Reset, "%s: reset gelato component", __FUNCTION__);
+}
+
+static void CODEC_GetTypeAndID(int *type, unsigned char *id) {
+    LOGI(CODEC_GetTypeAndID, "%s: Get type and ID for gelato component", __FUNCTION__);
+    *type = COMPONENT_TYPE_CODEC;
+    //CODEC_RegGet(CODEC_ID_REG, id);
+    *id = 0x0;
+}
+
+static ACH_ReturnCode CODEC_Handle(void *setting) {
+    ACH_ComponentParameter *param = (ACH_ComponentParameter *)setting;
+    unsigned short i = 0;
+    unsigned char numid, value, cache_idx;
+
+    if (param && param->i2c.reg_value) {
+        numid = CODEC_GetRegNumId(param->i2c.reg_index);
+        if (numid > 0) {
+            if (param->i2c.length == 1) {
+                //compare with register cache
+                cache_idx = numid - REG_NUMID_BASE;
+                //value = (reg_cache[cache_idx].reg_value & ~param->i2c.reg_mask) | (*param->i2c.reg_value);
+                //if ((reg_cache[cache_idx].reg_value & param->i2c.reg_mask) != (*param->i2c.reg_value)) {
+                value = (((*param->i2c.reg_value) << param->i2c.reg_shift) & param->i2c.reg_mask);
+                if ((reg_cache[cache_idx].reg_value & param->i2c.reg_mask) != value) {
+#ifdef DEBUG_CODEC
+                    LOGI(CODEC_Handle, "%s: set register 0x%02x [0x%02x --> 0x%02x]",
+                        __FUNCTION__,
+                        param->i2c.reg_index,
+                        reg_cache[cache_idx].reg_value,
+                        (reg_cache[cache_idx].reg_value & ~param->i2c.reg_mask) | value);
+#endif
+                    //reg_cache[cache_idx].reg_value = value;
+                    reg_cache[cache_idx].reg_value = (reg_cache[cache_idx].reg_value & ~param->i2c.reg_mask) | value;
+                    CODEC_RegSet(numid, reg_cache[cache_idx].reg_value);
+                } else {
+#ifdef DEBUG_CODEC
+                    LOGI(CODEC_Handle1, "%s: set register 0x%02x [0x%02x --> 0x%02x] (unchanged)",
+                        __FUNCTION__,
+                        param->i2c.reg_index,
+                        reg_cache[cache_idx].reg_value,
+                        reg_cache[cache_idx].reg_value);
+#endif
+                }
+            } else if (param->i2c.length > 1) {
+                //FIXME current no register cache is provided for mixer/eq configuration
+#ifdef DEBUG_CODEC
+                LOGI(CODEC_Handle2, "%s: set register 0x%02x values:", __FUNCTION__, param->i2c.reg_index);
+                for (i = 0; i < param->i2c.length; i++) {
+                    LOGI(CODEC_Handle3, "%s: \t\t\t    -->0x%02x", __FUNCTION__, param->i2c.reg_value[i]);
+                }
+#endif
+
+                CODEC_RegBurstSet(numid, param->i2c.length, param->i2c.reg_value);
+            }
+        }
+    }
+
+    return ACH_RC_OK;
+}
diff --git a/marvell/services/audio/libacm/acm/src/acm_gpio.c b/marvell/services/audio/libacm/acm/src/acm_gpio.c
new file mode 100644
index 0000000..b42408b
--- /dev/null
+++ b/marvell/services/audio/libacm/acm/src/acm_gpio.c
@@ -0,0 +1,127 @@
+/*
+* 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_ach_gpio"
+#define LOG_NDEBUG 0
+
+#include <cutils/log.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include "acm_ach.h"
+
+#ifndef GPIO_SPKR_SWITCH_PATH
+#define GPIO_SPKR_SWITCH_PATH "/sys/bus/platform/devices/88pm80x-codec/gpio_speaker_switch_select"
+#endif
+
+static void GPIO_Enable(void);
+static void GPIO_Disable(void);
+static void GPIO_Reset(void);
+static void GPIO_GetTypeAndID(int *type, unsigned char *id);
+static ACH_ReturnCode GPIO_Handle(void *setting);
+
+ACH_ComponentHandler gpio_handler = {
+    COMPONENT_INACTIVE,
+    0,
+    GPIO_Enable,
+    GPIO_Disable,
+    GPIO_Reset,
+    GPIO_GetTypeAndID,
+    GPIO_Handle,
+};
+
+static void GPIO_Set(unsigned char port, unsigned char value) {
+    //FIXME only can manipulate the specific port(GPIO19)
+    char buf[2];
+    int gpio_fd = open(GPIO_SPKR_SWITCH_PATH, O_RDWR | O_SYNC);
+
+    if (gpio_fd == -1) {
+        ALOGW(GPIO_Set, "%s: Failed to open GPIO %d, %s", __FUNCTION__, port,
+                strerror(errno));
+        return;
+    }
+
+    buf[1] = '\n';
+    if (value == 1) {
+        buf[0] = '1';
+    } else {
+        buf[0] = '0';
+    }
+    write(gpio_fd, buf, sizeof(buf));
+
+    close(gpio_fd);
+}
+
+static void GPIO_Get(unsigned char port, unsigned char *value) {
+    //FIXME only can manipulate the specific port(GPIO19)
+    int gpio_fd = open(GPIO_SPKR_SWITCH_PATH, O_RDONLY);
+    if (gpio_fd == -1) {
+        ALOGW(GPIO_Get, "%s: Failed to open GPIO %d, %s", __FUNCTION__, port,
+        strerror(errno));
+        return;
+    }
+    read(gpio_fd, value, sizeof(unsigned char));
+    close(gpio_fd);
+}
+
+//--------------------------------------------------------------
+//-------- External ACH APIs
+//--------------------------------------------------------------
+static void GPIO_Enable(void) {
+    ALOGI(GPIO_Enable, "%s: enable gpio component", __FUNCTION__);
+    // implemented if GPIO component needs
+    // GPIOEnable();
+    usleep(2000);
+}
+
+static void GPIO_Disable(void) {
+    ALOGI(GPIO_Disable, "%s: disable gpio component", __FUNCTION__);
+    // implemented if GPIO component needs
+    // GPIODisable();
+    usleep(2000);
+}
+
+static void GPIO_Reset(void) {
+    ALOGI(GPIO_Reset, "%s: reset gpio component", __FUNCTION__);
+}
+
+static void GPIO_GetTypeAndID(int *type, unsigned char *id) {
+    ALOGI(GPIO_GetTypeAndID, "%s: Get type and ID for GPIO component", __FUNCTION__);
+    *type = COMPONENT_TYPE_GPIO;
+    // implemented if GPIO component needs id
+    //GPIO_Get(GPIO_ID, id);
+}
+
+static ACH_ReturnCode GPIO_Handle(void *setting) {
+    ACH_ComponentParameter *param = (ACH_ComponentParameter *)setting;
+
+    if (param) {
+        ALOGI(GPIO_Handle, "%s: set GPIO port %d [%d]", __FUNCTION__,
+            param->gpio.gpio_port, param->gpio.gpio_value);
+        GPIO_Set(param->gpio.gpio_port, param->gpio.gpio_value);
+    }
+
+    return ACH_RC_OK;
+}
diff --git a/marvell/services/audio/libacm/acm/src/acm_i2c_adaptor.c b/marvell/services/audio/libacm/acm/src/acm_i2c_adaptor.c
new file mode 100644
index 0000000..16ba6f1
--- /dev/null
+++ b/marvell/services/audio/libacm/acm/src/acm_i2c_adaptor.c
@@ -0,0 +1,326 @@
+/*
+ * 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.
+ *
+ */
+
+
+/***********************************************************************
+ * NOTE 1:   "acm_I2C_adaptor"
+ * ---------------------------
+ * The name "acm_I2C_adaptor" is quite confusing!
+ * This adaptor does NOT dealing with real I2C register-numbers, but with
+ * ALSA (Advanced Linux Sound Architecture) "numid" element-numbers
+ *
+ * The relationship between I2C-Real-Reg and numid is next:
+ * - Real I2C-Regs provided by .XML on upper User-layer
+ * - It is converted into "numid" by xx_GetRegNumId(){_RegisterCache reg_cache[]}
+ * - I2CRead(), I2CBurstRead(), I2CWrite(), I2CBurstWrite()
+ *        are called with input "numid" having "wrong name" I2CRegAddr
+ * - "numid" passed into mixer and tiny-alsa which calls for ALSA-Kernel-Driver
+ * - On KERNEL-space, the ALSA is called with numid-- (minus 1!),
+ *   translated back to I2C Register and only then goes into i2c_pxa_xfer()
+ *
+ * NOTE 2: "Burst" Read/Write (in I2C Kernel this mode called BLOCK Read/Write)
+ * - The BLOCK Read/Write has limit max 32bytes
+ * - The "size" of the BLOCK is given in data[0]; the "size" and data[0] should
+ *  conform each other.
+ * - Write Data follows the size data[0] (e.g. data[1], data[2]...)
+ * - Read data is started from data[0] and so OVERWRITES the size
+ *
+ * NOTE 3:  "Burst" and "size" parameter
+ *  "Burst" data array could include more then one I2C request
+ *  (e.g. there could be more than one i2c-burst) and therefore
+ *  the "size" may be bigger than data[0]. The {struct snd_ctl_elem_value}
+ *  is big enough to keep them, the "size" just limits copy-size.
+ *
+ * NOTE 4: "Advanced/Extended ALSA"
+ *  One-By-One chain of transactions generated by User to Kernel-ALSA"
+ *  is expensive. It could be optimized by new "CHAIN/BURST" mode where
+ *  a burts/chain of transactions sent by User in the data-array by ONE(!)
+ *  IOCTL transaction for a chain of I2C transactions in Kernel-ALSA
+ *  This is "TBD feature"
+ */
+
+#define LOG_TAG "acm_i2c_adaptor"
+#define LOG_NDEBUG 0
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <cutils/log.h>
+#include <tinyalsa/asoundlib.h>
+#include <acm_debug.h>
+
+#define CARD_FOR_I2C 0
+
+#define ACM_I2C_BURST_READ_ENA
+#define ACM_I2C_BURST_WRITE_ENA
+
+/* Prototypes to avoid Warning on global APIs */
+int I2CInit(void);
+int I2CDeInit(void);
+int I2CRead(unsigned char I2CRegAddr, unsigned char *I2CRegData);
+int I2CBurstRead(unsigned char I2CRegAddr, unsigned char *I2CRegData, int size, int offset);
+void I2CWrite(unsigned char I2CRegAddr, unsigned short I2CRegData);
+void I2CBurstWrite(unsigned char I2CRegAddr, unsigned char size, unsigned char *I2CRegData);
+
+static struct mixer *i2c_mixer = NULL;
+static int mixer_ref_count = 0;
+
+int I2CInit() {
+    int card = CARD_FOR_I2C;
+
+    if (mixer_ref_count == 0) {
+        i2c_mixer = mixer_open(card);
+        if (i2c_mixer == NULL) {
+            ALOGE(I2CInit, "I2CInit: Failed to open mixer");
+            return -1;
+        }
+    }
+
+    mixer_ref_count++;
+#ifdef DEBUG_ADAPTOR
+    ALOGI(I2CInit1, "I2CInit: Init suscessfully, ref count %d", mixer_ref_count);
+#endif
+    return 0;
+}
+
+int I2CDeInit() {
+    mixer_ref_count--;
+
+    if ((mixer_ref_count == 0) && (i2c_mixer != NULL)) {
+        mixer_close(i2c_mixer);
+        i2c_mixer = NULL;
+    } else if (mixer_ref_count < 0) {
+        // if some error happened in mixer_open, reset count here.
+        ALOGW(I2CDeInit, "I2CDeInit: init/deinit mismatch! ref count %d", mixer_ref_count);
+        mixer_ref_count = 0;
+    }
+
+#ifdef DEBUG_ADAPTOR
+    ALOGI(I2CDeInit1, "I2CDeInit finished, ref count %d", mixer_ref_count);
+#endif
+    return 0;
+}
+
+int I2CRead(unsigned char I2CRegAddr, unsigned char *I2CRegData) {
+    int err = 0;
+    int result = 0;
+    struct mixer_ctl *ctl;
+    enum mixer_ctl_type type;
+
+    int numid = I2CRegAddr; /*see NOTE 1: "acm_I2C_adaptor" above */
+
+    if (!i2c_mixer) {
+        ALOGE(I2CRead, "%s: Make sure to open mixer before use it!", __FUNCTION__);
+        return -1;
+    }
+
+    ctl = mixer_get_ctl(i2c_mixer, numid);
+
+    if (!ctl) {
+        ALOGE(I2CRead1, "Invalid mixer control");
+        err = -1;
+        goto error_handle;
+    }
+
+    type = mixer_ctl_get_type(ctl);
+
+    switch(type) {
+        case MIXER_CTL_TYPE_INT:
+        case MIXER_CTL_TYPE_BOOL:
+        case MIXER_CTL_TYPE_ENUM:
+            result = mixer_ctl_get_value(ctl, 0);
+            if (result < 0) {
+                ALOGE(I2CRead2, "Error: invalid value");
+                err = -1;
+                goto error_handle;
+            }
+            *I2CRegData = result;
+            break;
+        default:
+            ALOGE(I2CRead3, "%s: invalid type %d", __FUNCTION__, type);
+            break;
+    }
+
+#ifdef DEBUG_ADAPTOR
+    ALOGI(I2CRead4, "%s: type = %d, numid = %d, data = 0x%02x",
+        __FUNCTION__, type, numid, *I2CRegData);
+#endif
+
+error_handle:
+    return err;
+}
+
+int I2CBurstRead(unsigned char I2CRegAddr, unsigned char *I2CRegData, int size, int offset)
+{
+#if !defined ACM_I2C_BURST_READ_ENA
+	I2CRegAddr = I2CRegAddr;
+	I2CRegData = I2CRegData;
+	size = size;
+	offset = offset;
+	return 0;
+#else
+    int i;
+    int result = 0;
+    struct mixer_ctl *ctl;
+    enum mixer_ctl_type type;
+	int data32[34];
+
+    int numid = I2CRegAddr; /*see NOTE 1: "acm_I2C_adaptor" above */
+
+	/* The "size" is not checked nor in mixer nor in Kernel
+	 * but I2C-SMBus protocol processes only 32 bytes ignoring others */
+	data32[0] = size; /* push size into data-array */
+
+    if (!i2c_mixer) {
+        ALOGE(I2CBurstRead, "%s: Make sure to open mixer before use it!", __FUNCTION__);
+        return -1;
+    }
+
+    ctl = mixer_get_ctl(i2c_mixer, numid);
+
+    if (!ctl) {
+        ALOGE(I2CBurstRead1, "Invalid mixer control");
+        goto error_handle;
+    }
+
+    type = mixer_ctl_get_type(ctl);
+
+	if (type != MIXER_CTL_TYPE_INT) {
+		ALOGE(I2CBurstRead2, "%s: invalid type %d", __FUNCTION__, type);
+		goto error_handle;
+	}
+
+	result = mixer_ctl_get_array(ctl, data32, size);
+	if (result) {
+		ALOGE(I2CBurstRead3, "Error: burst-read numid=%d size=%d failed(%d)(%s)", numid, size, errno, strerror(errno));
+		goto error_handle;
+	}
+	for (i=0; i < size; i++)
+		I2CRegData[i] = (unsigned char)data32[i];
+
+#ifdef DEBUG_ADAPTOR
+    ALOGI(I2CBurstRead4, "%s: type = %d, size = %d, numid = %d, data = 0x%02x %02x",
+        __FUNCTION__, type, size, numid, I2CRegData[0], I2CRegData[1]);
+#endif
+	return 0;
+
+error_handle:
+    return -1;
+#endif
+}
+#define DEBUG_ADAPTOR
+void I2CWrite(unsigned char I2CRegAddr, unsigned short I2CRegData) {
+    struct mixer_ctl *ctl;
+    enum mixer_ctl_type type;
+
+    int numid = I2CRegAddr; /*see NOTE 1: "acm_I2C_adaptor" above */
+
+    if (!i2c_mixer) {
+        ALOGE(I2CWrite, "%s: Make sure to open mixer before use it!", __FUNCTION__);
+        return;
+    }
+
+    ctl = mixer_get_ctl(i2c_mixer, numid);
+
+    if (!ctl) {
+        ALOGE(I2CWrite1, "Invalid mixer control");
+        goto error_handle;
+    }
+
+    type = mixer_ctl_get_type(ctl);
+
+#ifdef DEBUG_ADAPTOR
+    LOGI(I2CWrite2, "%s: type = %d, numid = %d, data[0] = 0x%lx",
+        __FUNCTION__, type, numid, I2CRegData);
+#endif
+
+    switch(type) {
+        case MIXER_CTL_TYPE_INT:
+        case MIXER_CTL_TYPE_BOOL:
+        case MIXER_CTL_TYPE_ENUM:
+            if (mixer_ctl_set_value(ctl, 0, I2CRegData)) {
+                ALOGE(I2CWrite3, "Error: invalid value\n");
+                goto error_handle;
+            }
+            break;
+        default:
+            ALOGE(I2CWrite4, "%s: invalid type %d", __FUNCTION__, type);
+            break;
+    }
+
+error_handle:
+    return;
+}
+
+void I2CBurstWrite(unsigned char I2CRegAddr, unsigned char size, unsigned char *I2CRegData)
+{
+#if !defined ACM_I2C_BURST_WRITE_ENA
+	I2CRegAddr = I2CRegAddr;
+	I2CRegData = I2CRegData;
+	size = size;
+#else
+	int i;
+	struct mixer_ctl *ctl;
+	enum mixer_ctl_type type;
+	unsigned int data32[64], *dst;
+
+	int numid = I2CRegAddr; /*see NOTE 1: "acm_I2C_adaptor" above */
+
+	if (!i2c_mixer) {
+		ALOGE(I2CBurstWrite, "%s: Make sure to open mixer before use it!", __FUNCTION__);
+		return;
+	}
+
+	ctl = mixer_get_ctl(i2c_mixer, numid);
+
+	if (!ctl) {
+		ALOGE(I2CBurstWrite1, "Invalid mixer control");
+		goto end_handle;
+	}
+
+	type = mixer_ctl_get_type(ctl);
+
+	if (type != MIXER_CTL_TYPE_INT) {
+		ALOGE(I2CBurstWrite2, "%s: invalid type %d", __FUNCTION__, type);
+		goto end_handle;
+	}
+
+#ifdef DEBUG_ADAPTOR
+	ALOGI(I2CBurstWrite3, "%s: type = %d, size = %d, numid = %d, data[0] = 0x%02x %02x",
+		__FUNCTION__, type, size, numid, I2CRegData[0], I2CRegData[1]);
+#endif
+	/* I2C Burst (SMBUS BLOCK) data32 should have data-size on first place
+		* Add it to [0], and call mixer with size+1 */
+	data32[0] = size;
+	dst = &data32[1];
+	for (i=0; i < size; i++)
+		*dst++ = (int)I2CRegData[i] & 0xFF;
+	mixer_ctl_set_array(ctl, data32, size + 1);
+end_handle:
+	return;
+#endif
+}
+
diff --git a/marvell/services/audio/libacm/acm/src/acm_log.c b/marvell/services/audio/libacm/acm/src/acm_log.c
new file mode 100644
index 0000000..b2251e4
--- /dev/null
+++ b/marvell/services/audio/libacm/acm/src/acm_log.c
@@ -0,0 +1,35 @@
+/******************************************************************************
+*(C) Copyright 2014 Marvell International Ltd.
+* All Rights Reserved
+******************************************************************************/
+
+#ifdef PXA1826_AUDIO
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "acm_log.h"
+
+int __acm_log_print(int prio, const char *tag,  const char *fmt, ...)
+{
+    va_list ap;
+    char buf[LOG_BUF_SIZE];
+    int write_length;
+    (void)prio;
+
+    write_length    =   snprintf(buf,LOG_BUF_SIZE,"%s: ",tag);
+    if ((write_length != 0) && (LOG_BUF_SIZE > write_length + 2)) {
+        va_start(ap, fmt);
+        write_length += vsnprintf(&buf[write_length], LOG_BUF_SIZE - write_length - 2, fmt, ap);
+        va_end(ap);
+        buf[write_length++] =   '\n';
+        buf[write_length++] =   '\0';
+        printf(buf);
+    }
+
+    return write_length;
+}
+#endif//PXA1826_AUDIO
diff --git a/marvell/services/audio/libacm/acm/src/acm_nau8810.h b/marvell/services/audio/libacm/acm/src/acm_nau8810.h
new file mode 100644
index 0000000..5183cfe
--- /dev/null
+++ b/marvell/services/audio/libacm/acm/src/acm_nau8810.h
@@ -0,0 +1,218 @@
+/*
+ * ASR Audio path definition of NAU8810 
+ *
+ * Copyright (C) 2018 ASR Microelectronic Ltd.
+ *
+ * Author: Chen wen<wenchen@asrmicro.com>
+ *
+ * This file contains proprietary information.
+ * No dissemination allowed without prior written permission from
+ * ASR Microelectronic Ltd.
+ *
+ * File Description:
+ *
+ * This file contains header for audio path definition of NAU8810 
+ */
+
+#ifndef ACM_NAU8810_H
+#define ACM_NAU8810_H
+
+#define CODEC_NAU8810_VOICE_REG06       0x06
+#define CODEC_NAU8810_VOICE_MASTER      0x01   //bit0=1 master
+#define CODEC_NAU8810_VOICE_SLAVE       0x00   //bit0=0 slave
+
+
+#define CODEC_NAU8810_VOICE_REG07       0x07
+#define CODEC_NAU8810_VOICE_WB          0x06   //FS:16KHz, BCLK:256FS; Keep identical with the config when GSSP is master
+#define CODEC_NAU8810_VOICE_NB          0x0a   //FS:8KHz, BCLK:256FS
+
+//////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////
+/////////////////////////APH_PATH_ID_HIFIPLAYTOEARPHONE//////////////////////////
+ACMAPH_Register ACM_HiFiPlayToEarphone_Disable[]={
+    {NAU8810, 0x01, 0x00},{NAU8810, 0x02, 0x00},{NAU8810, 0x03, 0x00},{NAU8810, 0x31, 0x00},{NAU8810, 0x32, 0x00}
+};
+ACMAPH_Register ACM_HiFiPlayToEarphone_Enable[]={
+    {NAU8810, 0x04, 0x118},{NAU8810, 0x06, CODEC_NAU8810_VOICE_SLAVE},{NAU8810, 0x07, CODEC_NAU8810_VOICE_NB},{NAU8810, 0x24, 0x00},{NAU8810, 0x25, 0x00},{NAU8810, 0x26, 0x00},{NAU8810, 0x27, 0x00},
+    {NAU8810, 0x0e, 0x00},{NAU8810, 0x12, 0x00},{NAU8810, 0x13, 0x00},{NAU8810, 0x14, 0x00},{NAU8810, 0x15, 0x00},{NAU8810, 0x16, 0x00},{NAU8810, 0x1b, 0x00},
+    {NAU8810, 0x1c, 0x00},{NAU8810, 0x1d, 0x00},{NAU8810, 0x1e, 0x00},{NAU8810, 0x01, 0x19},{NAU8810, 0x02, 0x15},{NAU8810, 0x03, 0x89},{NAU8810, 0x19, 0x0c},
+    {NAU8810, 0x31, 0x0a},{NAU8810, 0x32, 0x00},{NAU8810, 0x36, 0x00}
+};
+
+/////////////////////////APH_PATH_ID_HIFIPLAYTOSPKR//////////////////////////
+ACMAPH_Register ACM_HiFiPlayToSPKR_Disable[]={
+    {NAU8810, 0x01, 0x00},{NAU8810, 0x02, 0x00},{NAU8810, 0x03, 0x00},{NAU8810, 0x31, 0x00},{NAU8810, 0x32, 0x00}
+};
+ACMAPH_Register ACM_HiFiPlayToSPKR_Enable[]={
+    {NAU8810, 0x04, 0x118},{NAU8810, 0x06, CODEC_NAU8810_VOICE_SLAVE},{NAU8810, 0x07, CODEC_NAU8810_VOICE_NB},{NAU8810, 0x24, 0x00},{NAU8810, 0x25, 0x00},{NAU8810, 0x26, 0x00},{NAU8810, 0x27, 0x00},
+    {NAU8810, 0x0e, 0x00},{NAU8810, 0x12, 0x00},{NAU8810, 0x13, 0x00},{NAU8810, 0x14, 0x00},{NAU8810, 0x15, 0x00},{NAU8810, 0x16, 0x00},{NAU8810, 0x1b, 0x00},
+    {NAU8810, 0x1c, 0x00},{NAU8810, 0x1d, 0x00},{NAU8810, 0x1e, 0x00},{NAU8810, 0x01, 0x19},{NAU8810, 0x02, 0x15},{NAU8810, 0x03, 0x65},{NAU8810, 0x19, 0x0c},
+    {NAU8810, 0x31, 0x02},{NAU8810, 0x32, 0x01},{NAU8810, 0x36, 0x20}
+};
+
+/////////////////////////APH_PATH_ID_HIFIPLAYTOHP//////////////////////////
+ACMAPH_Register ACM_HiFiPlayToHP_Disable[]={
+    {NAU8810, 0x01, 0x00},{NAU8810, 0x02, 0x00},{NAU8810, 0x03, 0x00},{NAU8810, 0x32, 0x00}
+};
+ACMAPH_Register ACM_HiFiPlayToHP_Enable[]={
+    {NAU8810, 0x04, 0x118},{NAU8810, 0x06, CODEC_NAU8810_VOICE_SLAVE},{NAU8810, 0x07, CODEC_NAU8810_VOICE_NB},{NAU8810, 0x24, 0x00},{NAU8810, 0x25, 0x00},{NAU8810, 0x26, 0x00},{NAU8810, 0x27, 0x00},
+    {NAU8810, 0x0e, 0x00},{NAU8810, 0x12, 0x00},{NAU8810, 0x13, 0x00},{NAU8810, 0x14, 0x00},{NAU8810, 0x15, 0x00},{NAU8810, 0x16, 0x00},{NAU8810, 0x1b, 0x00},
+    {NAU8810, 0x1c, 0x00},{NAU8810, 0x1d, 0x00},{NAU8810, 0x1e, 0x00},{NAU8810, 0x01, 0x19},{NAU8810, 0x02, 0x15},{NAU8810, 0x03, 0x65},{NAU8810, 0x19, 0x0c},
+    {NAU8810, 0x32, 0x01},{NAU8810, 0x36, 0x20}
+};
+
+/////////////////////////APH_PATH_ID_HIFIRECORDFROMMIC1//////////////////////////
+ACMAPH_Register ACM_HiFiRecordFromMic1_Disable[]={
+    {NAU8810, 0x01, 0x00},{NAU8810, 0x02, 0x00}
+};
+ACMAPH_Register ACM_HiFiRecordFromMic1_Enable[]={
+    {NAU8810, 0x04, 0x118},{NAU8810, 0x06, CODEC_NAU8810_VOICE_SLAVE},{NAU8810, 0x07, CODEC_NAU8810_VOICE_NB},{NAU8810, 0x24, 0x00},{NAU8810, 0x25, 0x00},{NAU8810, 0x26, 0x00},{NAU8810, 0x27, 0x00},
+    {NAU8810, 0x0e, 0x00},{NAU8810, 0x12, 0x00},{NAU8810, 0x13, 0x00},{NAU8810, 0x14, 0x00},{NAU8810, 0x15, 0x00},{NAU8810, 0x16, 0x00},{NAU8810, 0x1b, 0x00},
+    {NAU8810, 0x1c, 0x00},{NAU8810, 0x1d, 0x00},{NAU8810, 0x1e, 0x00},{NAU8810, 0x01, 0x19},{NAU8810, 0x02, 0x15},{NAU8810, 0x2c, 0x03},{NAU8810, 0x2d, 0x20},
+    {NAU8810, 0x2f, 0x00}
+};
+ACMAPH_Register ACM_HiFiRecordFromMic1_Mute[]={
+    {NAU8810, 0x02, 0x011},{NAU8810, 0x2c, 0x000},
+};
+ACMAPH_Register ACM_HiFiRecordFromMic1_UnMute[]={
+    {NAU8810, 0x02, 0x015},{NAU8810, 0x2c, 0x003},
+};
+/////////////////////////APH_PATH_ID_HIFIRECORDFROMHSMIC//////////////////////////
+ACMAPH_Register ACM_HiFiRecordFromHsMic_Disable[]={
+    {NAU8810, 0x01, 0x00},{NAU8810, 0x02, 0x00}
+};
+ACMAPH_Register ACM_HiFiRecordFromHsMic_Enable[]={
+    {NAU8810, 0x04, 0x118},{NAU8810, 0x06, CODEC_NAU8810_VOICE_SLAVE},{NAU8810, 0x07, CODEC_NAU8810_VOICE_NB},{NAU8810, 0x24, 0x00},{NAU8810, 0x25, 0x00},{NAU8810, 0x26, 0x00},{NAU8810, 0x27, 0x00},
+    {NAU8810, 0x0e, 0x00},{NAU8810, 0x12, 0x00},{NAU8810, 0x13, 0x00},{NAU8810, 0x14, 0x00},{NAU8810, 0x15, 0x00},{NAU8810, 0x16, 0x00},{NAU8810, 0x1b, 0x00},
+    {NAU8810, 0x1c, 0x00},{NAU8810, 0x1d, 0x00},{NAU8810, 0x1e, 0x00},{NAU8810, 0x01, 0x19},{NAU8810, 0x02, 0x15},{NAU8810, 0x2c, 0x03},{NAU8810, 0x2d, 0x20},
+    {NAU8810, 0x2f, 0x00}
+};
+ACMAPH_Register ACM_HiFiRecordFromHsMic_Mute[]={
+    {NAU8810, 0x02, 0x011},{NAU8810, 0x2c, 0x000},
+};
+ACMAPH_Register ACM_HiFiRecordFromHsMic_UnMute[]={
+    {NAU8810, 0x02, 0x015},{NAU8810, 0x2c, 0x003},
+};
+//////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////
+/////////////////////////APH_PATH_ID_VOICEPLAYTOEARPHONE//////////////////////////
+
+ACMAPH_Register ACM_VoicePlayToEarphone_Disable[]={
+    {NAU8810, 0x01, 0x00},{NAU8810, 0x02, 0x00},{NAU8810, 0x03, 0x00},{NAU8810, 0x31, 0x00}
+};
+ACMAPH_Register ACM_VoicePlayToEarphone_Enable[]={
+    {NAU8810, 0x04, 0x118},{NAU8810, 0x06, CODEC_NAU8810_VOICE_SLAVE},{NAU8810, 0x07, CODEC_NAU8810_VOICE_NB},{NAU8810, 0x24, 0x00},{NAU8810, 0x25, 0x00},{NAU8810, 0x26, 0x00},{NAU8810, 0x27, 0x00},
+    {NAU8810, 0x0e, 0x00},{NAU8810, 0x12, 0x00},{NAU8810, 0x13, 0x00},{NAU8810, 0x14, 0x00},{NAU8810, 0x15, 0x00},{NAU8810, 0x16, 0x00},{NAU8810, 0x1b, 0x00},
+    {NAU8810, 0x1c, 0x00},{NAU8810, 0x1d, 0x00},{NAU8810, 0x1e, 0x00},{NAU8810, 0x01, 0x19},{NAU8810, 0x02, 0x15},{NAU8810, 0x03, 0x89},{NAU8810, 0x19, 0x0c},
+    {NAU8810, 0x31, 0x0a},{NAU8810, 0x32, 0x00},{NAU8810, 0x36, 0x20}
+};
+
+/////////////////////////APH_PATH_ID_VOICEPLAYTOSPKR//////////////////////////
+ACMAPH_Register ACM_VoicePlayToSPKR_Disable[]={
+    {NAU8810, 0x01, 0x00},{NAU8810, 0x02, 0x00},{NAU8810, 0x03, 0x00},{NAU8810, 0x32, 0x00}
+};
+ACMAPH_Register ACM_VoicePlayToSPKR_Enable[]={
+    {NAU8810, 0x04, 0x118},{NAU8810, 0x06, CODEC_NAU8810_VOICE_SLAVE},{NAU8810, 0x07, CODEC_NAU8810_VOICE_NB},{NAU8810, 0x24, 0x00},{NAU8810, 0x25, 0x00},{NAU8810, 0x26, 0x00},{NAU8810, 0x27, 0x00},
+    {NAU8810, 0x0e, 0x00},{NAU8810, 0x12, 0x00},{NAU8810, 0x13, 0x00},{NAU8810, 0x14, 0x00},{NAU8810, 0x15, 0x00},{NAU8810, 0x16, 0x00},{NAU8810, 0x1b, 0x00},
+    {NAU8810, 0x1c, 0x00},{NAU8810, 0x1d, 0x00},{NAU8810, 0x1e, 0x00},{NAU8810, 0x01, 0x19},{NAU8810, 0x02, 0x15},{NAU8810, 0x03, 0x65},{NAU8810, 0x19, 0x0c},
+    {NAU8810, 0x31, 0x02},{NAU8810, 0x32, 0x01},{NAU8810, 0x36, 0x20}
+};
+
+/////////////////////////APH_PATH_ID_VOICEPLAYTOHP//////////////////////////
+ACMAPH_Register ACM_VoicePlayToHP_Disable[]={
+    {NAU8810, 0x01, 0x00},{NAU8810, 0x02, 0x00},{NAU8810, 0x03, 0x00},{NAU8810, 0x32, 0x00}
+};
+ACMAPH_Register ACM_VoicePlayToHP_Enable[]={
+    {NAU8810, 0x04, 0x118},{NAU8810, 0x06, CODEC_NAU8810_VOICE_SLAVE},{NAU8810, 0x07, CODEC_NAU8810_VOICE_NB},{NAU8810, 0x24, 0x00},{NAU8810, 0x25, 0x00},{NAU8810, 0x26, 0x00},{NAU8810, 0x27, 0x00},
+    {NAU8810, 0x0e, 0x00},{NAU8810, 0x12, 0x00},{NAU8810, 0x13, 0x00},{NAU8810, 0x14, 0x00},{NAU8810, 0x15, 0x00},{NAU8810, 0x16, 0x00},{NAU8810, 0x1b, 0x00},
+    {NAU8810, 0x1c, 0x00},{NAU8810, 0x1d, 0x00},{NAU8810, 0x1e, 0x00},{NAU8810, 0x01, 0x19},{NAU8810, 0x02, 0x15},{NAU8810, 0x03, 0x65},{NAU8810, 0x19, 0x0c},
+    {NAU8810, 0x32, 0x01},{NAU8810, 0x36, 0x20}
+};
+
+/////////////////////////APH_PATH_ID_VOICERECORDFROMMIC1//////////////////////////
+ACMAPH_Register ACM_VoiceRecordFromMic1_Disable[]={
+    {NAU8810, 0x01, 0x00},{NAU8810, 0x02, 0x00}
+};
+ACMAPH_Register ACM_VoiceRecordFromMic1_Enable[]={
+    {NAU8810, 0x04, 0x118},{NAU8810, 0x06, CODEC_NAU8810_VOICE_SLAVE},{NAU8810, 0x07, CODEC_NAU8810_VOICE_NB},{NAU8810, 0x24, 0x00},{NAU8810, 0x25, 0x00},{NAU8810, 0x26, 0x00},{NAU8810, 0x27, 0x00},
+    {NAU8810, 0x0e, 0x00},{NAU8810, 0x12, 0x00},{NAU8810, 0x13, 0x00},{NAU8810, 0x14, 0x00},{NAU8810, 0x15, 0x00},{NAU8810, 0x16, 0x00},{NAU8810, 0x1b, 0x00},
+    {NAU8810, 0x1c, 0x00},{NAU8810, 0x1d, 0x00},{NAU8810, 0x1e, 0x00},{NAU8810, 0x01, 0x19},{NAU8810, 0x02, 0x15},{NAU8810, 0x2c, 0x03},{NAU8810, 0x2d, 0x20},
+    {NAU8810, 0x2f, 0x00}
+};
+ACMAPH_Register ACM_VoiceRecordFromMic1_Mute[]={
+    {NAU8810, 0x02, 0x011},{NAU8810, 0x2c, 0x000},
+};
+ACMAPH_Register ACM_VoiceRecordFromMic1_UnMute[]={
+    {NAU8810, 0x02, 0x015},{NAU8810, 0x2c, 0x003},
+};
+/////////////////////////APH_PATH_ID_VOICERECORDFROMHSMIC//////////////////////////
+ACMAPH_Register ACM_VoiceRecordFromHsMic_Disable[]={
+    {NAU8810, 0x01, 0x00},{NAU8810, 0x02, 0x00}
+};
+ACMAPH_Register ACM_VoiceRecordFromHsMic_Enable[]={
+    {NAU8810, 0x04, 0x118},{NAU8810, 0x06, CODEC_NAU8810_VOICE_SLAVE},{NAU8810, 0x07, CODEC_NAU8810_VOICE_NB},{NAU8810, 0x24, 0x00},{NAU8810, 0x25, 0x00},{NAU8810, 0x26, 0x00},{NAU8810, 0x27, 0x00},
+    {NAU8810, 0x0e, 0x00},{NAU8810, 0x12, 0x00},{NAU8810, 0x13, 0x00},{NAU8810, 0x14, 0x00},{NAU8810, 0x15, 0x00},{NAU8810, 0x16, 0x00},{NAU8810, 0x1b, 0x00},
+    {NAU8810, 0x1c, 0x00},{NAU8810, 0x1d, 0x00},{NAU8810, 0x1e, 0x00},{NAU8810, 0x01, 0x19},{NAU8810, 0x02, 0x15},{NAU8810, 0x2c, 0x03},{NAU8810, 0x2d, 0x20},
+    {NAU8810, 0x2f, 0x00}
+};
+ACMAPH_Register ACM_VoiceRecordFromHsMic_Mute[]={
+    {NAU8810, 0x02, 0x011},{NAU8810, 0x2c, 0x000},
+};
+ACMAPH_Register ACM_VoiceRecordFromHsMic_UnMute[]={
+    {NAU8810, 0x02, 0x015},{NAU8810, 0x2c, 0x003},
+};
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+static ACMAPH_Component ACM_Disable[APH_PATH_ID_CNT]={
+    {APH_PATH_ID_HIFIPLAYTOEARPHONE,    ACM_HiFiPlayToEarphone_Disable,     sizeof(ACM_HiFiPlayToEarphone_Disable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIPLAYTOSPKR,        ACM_HiFiPlayToSPKR_Disable,         sizeof(ACM_HiFiPlayToSPKR_Disable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIPLAYTOHP,          ACM_HiFiPlayToHP_Disable,           sizeof(ACM_HiFiPlayToHP_Disable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIRECORDFROMMIC1,    ACM_HiFiRecordFromMic1_Disable,     sizeof(ACM_HiFiRecordFromMic1_Disable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIRECORDFROMHSMIC,   ACM_HiFiRecordFromHsMic_Disable,    sizeof(ACM_HiFiRecordFromHsMic_Disable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICEPLAYTOEARPHONE,   ACM_VoicePlayToEarphone_Disable,    sizeof(ACM_VoicePlayToEarphone_Disable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICEPLAYTOSPKR,       ACM_VoicePlayToSPKR_Disable,        sizeof(ACM_VoicePlayToSPKR_Disable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICEPLAYTOHP,         ACM_VoicePlayToHP_Disable,          sizeof(ACM_VoicePlayToHP_Disable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICERECORDFROMMIC1,   ACM_VoiceRecordFromMic1_Disable,    sizeof(ACM_VoiceRecordFromMic1_Disable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICERECORDFROMHSMIC,  ACM_VoiceRecordFromHsMic_Disable,   sizeof(ACM_VoiceRecordFromHsMic_Disable)/sizeof(ACMAPH_Register)},
+};
+
+static ACMAPH_Component ACM_Enable[APH_PATH_ID_CNT]={
+    {APH_PATH_ID_HIFIPLAYTOEARPHONE,    ACM_HiFiPlayToEarphone_Enable,      sizeof(ACM_HiFiPlayToEarphone_Enable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIPLAYTOSPKR,        ACM_HiFiPlayToSPKR_Enable,          sizeof(ACM_HiFiPlayToSPKR_Enable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIPLAYTOHP,          ACM_HiFiPlayToHP_Enable,            sizeof(ACM_HiFiPlayToHP_Enable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIRECORDFROMMIC1,    ACM_HiFiRecordFromMic1_Enable,      sizeof(ACM_HiFiRecordFromMic1_Enable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIRECORDFROMHSMIC,   ACM_HiFiRecordFromHsMic_Enable,     sizeof(ACM_HiFiRecordFromHsMic_Enable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICEPLAYTOEARPHONE,   ACM_VoicePlayToEarphone_Enable,     sizeof(ACM_VoicePlayToEarphone_Enable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICEPLAYTOSPKR,       ACM_VoicePlayToSPKR_Enable,         sizeof(ACM_VoicePlayToSPKR_Enable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICEPLAYTOHP,         ACM_VoicePlayToHP_Enable,           sizeof(ACM_VoicePlayToHP_Enable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICERECORDFROMMIC1,   ACM_VoiceRecordFromMic1_Enable,     sizeof(ACM_VoiceRecordFromMic1_Enable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICERECORDFROMHSMIC,  ACM_VoiceRecordFromHsMic_Enable,    sizeof(ACM_VoiceRecordFromHsMic_Enable)/sizeof(ACMAPH_Register)},
+};
+
+static ACMAPH_Component ACM_Mute[APH_PATH_IN_CNT]={
+    {APH_PATH_ID_HIFIRECORDFROMMIC1,    ACM_HiFiRecordFromMic1_Mute,      sizeof(ACM_HiFiRecordFromMic1_Mute)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIRECORDFROMHSMIC,   ACM_HiFiRecordFromHsMic_Mute,     sizeof(ACM_HiFiRecordFromHsMic_Mute)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICERECORDFROMMIC1,   ACM_VoiceRecordFromMic1_Mute,     sizeof(ACM_VoiceRecordFromMic1_Mute)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICERECORDFROMHSMIC,  ACM_VoiceRecordFromHsMic_Mute,    sizeof(ACM_VoiceRecordFromHsMic_Mute)/sizeof(ACMAPH_Register)},
+};
+static ACMAPH_Component ACM_UnMute[APH_PATH_IN_CNT]={
+    {APH_PATH_ID_HIFIRECORDFROMMIC1,    ACM_HiFiRecordFromMic1_UnMute,      sizeof(ACM_HiFiRecordFromMic1_UnMute)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIRECORDFROMHSMIC,   ACM_HiFiRecordFromHsMic_UnMute,     sizeof(ACM_HiFiRecordFromHsMic_UnMute)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICERECORDFROMMIC1,   ACM_VoiceRecordFromMic1_UnMute,     sizeof(ACM_VoiceRecordFromMic1_UnMute)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICERECORDFROMHSMIC,  ACM_VoiceRecordFromHsMic_UnMute,    sizeof(ACM_VoiceRecordFromHsMic_UnMute)/sizeof(ACMAPH_Register)},
+};
+
+extern ACH_ComponentHandler NAU8810_handler;
+
+static APH_ACHComponent ACH_component_table[] = {
+    {NAU8810, &NAU8810_handler},
+};
+//Sorted as APH_AudioComponent
+static char APH_AudioComponent_Name[][16]= {
+    "ELBA",
+    "USTICA",
+    "DELAY",
+    "NAU8810",
+    "ALC5616"
+} ;
+#endif
diff --git a/marvell/services/audio/libacm/acm/src/acm_nau8810_handle.c b/marvell/services/audio/libacm/acm/src/acm_nau8810_handle.c
new file mode 100644
index 0000000..aca167f
--- /dev/null
+++ b/marvell/services/audio/libacm/acm/src/acm_nau8810_handle.c
@@ -0,0 +1,229 @@
+/*
+ * 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_ach_nau8810"
+#define LOG_NDEBUG 0
+
+#include <cutils/log.h>
+#include "acm_nau8810_handle.h"
+
+int codec_reg_num = NUM_OF_REGS;
+
+static void NAU8810_Enable(void);
+static void NAU8810_Disable(void);
+static void NAU8810_Reset(void);
+static void NAU8810_GetTypeAndID(int *type, unsigned char *id);
+static ACH_ReturnCode NAU8810_Handle(void *setting);
+
+ACH_ComponentHandler NAU8810_handler = {
+    COMPONENT_INACTIVE,
+    0,
+    NAU8810_Enable,
+    NAU8810_Disable,
+    NAU8810_Reset,
+    NAU8810_GetTypeAndID,
+    NAU8810_Handle,
+};
+
+extern int I2CInit(void);
+extern int I2CDeInit(void);
+extern void I2CWrite(unsigned char numid, unsigned short value);
+extern void I2CBurstWrite(unsigned char numid, unsigned char size, unsigned char *value);
+extern void I2CRead(unsigned char numid, unsigned char *value);
+extern void I2CBurstRead(unsigned char numid, unsigned char *value, int size, int offset);
+
+#ifdef PXA1826_AUDIO
+#ifndef ACM_ALSA_INIT
+#define ACM_ALSA_INIT
+#endif
+#endif
+
+#ifdef DEBUG_FAKE_ACH
+#undef ACM_ALSA_INIT
+#endif
+
+
+static void NAU8810_RegSet(unsigned char numid, unsigned short value) {
+#ifndef DEBUG_FAKE_ACH
+    I2CWrite(numid, value);
+#else
+    LOGD(NAU8810_RegSet, "  FAKE_ACH: %s(0x%x, 0x%x)", __FUNCTION__, numid, value);
+#endif
+}
+
+static void NAU8810_RegBurstSet(unsigned char numid, unsigned char size, unsigned char *value) {
+#ifndef DEBUG_FAKE_ACH
+    I2CBurstWrite(numid, size, value);
+#else
+    LOGD(NAU8810_RegBurstSet, "  FAKE_ACH: %s(0x%x, 0x%x, ..)", __FUNCTION__, numid, size);
+#endif
+}
+
+void NAU8810_RegGet(unsigned char numid, unsigned char *value) {
+#ifndef DEBUG_FAKE_ACH
+    I2CRead(numid, value);
+#else
+    LOGD(NAU8810_RegGet, "  FAKE_ACH: %s(0x%x, ..)", __FUNCTION__, numid);
+#endif
+}
+
+void NAU8810_RegBurstGet(unsigned char numid, unsigned char *value, int size, int offset) {
+#ifndef DEBUG_FAKE_ACH
+    I2CBurstRead(numid, value, size, offset);
+#else
+    LOGD(NAU8810_RegBurstGet, "  FAKE_ACH: %s(0x%x, .., 0x%x, 0x%x)", __FUNCTION__, numid, size, offset);
+#endif
+}
+
+static void NAU8810_ResetRegCache() {
+    int size = sizeof(reg_cache) / sizeof(reg_cache[0]);
+    int i = 0;
+
+    for (i = 0; i < size; i++) {
+        reg_cache[i].reg_value = reg_cache[i].reg_default;
+    }
+}
+
+unsigned char NAU8810_GetRegNumId(unsigned char reg_index) {
+    unsigned char i = 0;
+
+    for (i = 0; i < NUM_OF_REGS; i++) {
+        if (reg_cache[i].reg_index == reg_index) {
+            return REG_NUMID_BASE + i;
+        }
+    }
+
+    return 0;
+}
+
+//--------------------------------------------------------------
+//-------- External ACH APIs
+//--------------------------------------------------------------
+#ifdef ACM_ALSA_INIT
+// NOTE about pair Enable/Disable
+//  On startup Disable could be called without Enable as Init/Reset sequence
+//  Let's "force" I2CInit() for first only Disable without Enable
+//
+static int _acm_initialized = 0;
+#endif
+
+static void NAU8810_Enable(void) {
+    LOGI(NAU8810_Enable, "%s: enable NAU8810 component", __FUNCTION__);
+
+#ifdef ACM_ALSA_INIT
+    LOGI(NAU8810_Enable, "%s: _acm_initialized=%d!", __FUNCTION__, _acm_initialized);
+    _acm_initialized = 1;
+    I2CInit(); //adaptor to alsa-mixer
+#endif
+
+}
+
+static void NAU8810_Disable(void) {
+    LOGI(NAU8810_Disable, "%s: disable NAU8810 component", __FUNCTION__);
+
+#ifdef ACM_ALSA_INIT
+    if (!_acm_initialized) {
+        _acm_initialized = 1;
+        I2CInit(); //adaptor to alsa-mixer
+    }
+#endif
+
+#ifdef ACM_ALSA_INIT
+    I2CDeInit(); //adaptor to alsa-mixer
+#endif
+}
+
+static void NAU8810_Reset(void) {
+    LOGI(NAU8810_Reset, "%s: Reset NAU8810 registers!", __FUNCTION__);
+    int size = sizeof(reg_cache) / sizeof(reg_cache[0]);
+    int size_col = sizeof(reg_cache[0]) / sizeof(unsigned char);
+    int i, k = 0;
+    unsigned char j, numid, value, cache_idx;
+    NAU8810_RegisterCache reg_cache_inorder[size];
+
+#ifdef ACM_ALSA_INIT
+    I2CInit(); //make sure to enable mixer before and close after this operation
+#endif
+
+#ifdef ACM_ALSA_INIT
+    I2CDeInit(); //make sure to enable mixer before and close after this operation
+#endif
+}
+
+static void NAU8810_GetTypeAndID(int *type, unsigned char *id) {
+#ifdef ACM_ALSA_INIT
+    I2CInit(); //make sure to enable mixer before and close after this operation
+#endif
+    LOGI(Elba_GetTypeAndID, "%s: Get type and ID for elba component", __FUNCTION__);
+    *type = COMPONENT_TYPE_CODEC;
+    NAU8810_RegGet(NAU8810_ID_REG, id);
+#ifdef ACM_ALSA_INIT
+    I2CDeInit(); //make sure to enable mixer before and close after this operation
+#endif
+}
+
+static ACH_ReturnCode NAU8810_Handle(void *setting) {
+    ACH_ComponentParameter *param = (ACH_ComponentParameter *)setting;
+    unsigned short i = 0;
+    unsigned short numid, value, cache_idx;
+
+    if (param && param->i2c.reg_value) {
+        numid = NAU8810_GetRegNumId(param->i2c.reg_index);
+
+        LOGI(NAU8810_Handle, "%s: REG_NUMID_BASE=%d, numid=%d. set register 0x%lx values:0x%lx ",
+                __FUNCTION__, REG_NUMID_BASE, numid, param->i2c.reg_index,  *(param->i2c.reg_value));
+
+        if (numid > 0) {
+            if (param->i2c.length == 2) {
+                //compare with register cache
+                cache_idx = numid - REG_NUMID_BASE;
+                value = (*param->i2c.reg_value);
+
+#ifdef DEBUG_NAU8810
+                LOGI(NAU8810_Handle, "%s: cache_idx=%d, numid=%d. set register 0x%lx [0x%lx --> 0x%lx]",
+                        __FUNCTION__,
+                        cache_idx,
+                        numid,
+                        param->i2c.reg_index,
+                        reg_cache[cache_idx].reg_value,
+                        value);
+#endif
+                reg_cache[cache_idx].reg_value = value;
+                NAU8810_RegSet(numid, value);
+
+            } else if (param->i2c.length > 2) {
+                //FIXME current no register cache is provided for mixer/eq configuration
+#ifdef DEBUG_NAU8810
+                LOGI(NAU8810_Handle2, "%s: numid=%d. set register 0x%lx values:", __FUNCTION__, numid, param->i2c.reg_index);
+                for (i = 0; i < param->i2c.length; i++) {
+                    LOGI(NAU8810_Handle3, "%s: \t\t\t    -->0x%lx", __FUNCTION__, param->i2c.reg_value[i]);
+                }
+#endif
+
+                NAU8810_RegBurstSet(numid, param->i2c.length, param->i2c.reg_value);
+            }
+        }
+    }
+
+    return ACH_RC_OK;
+}
diff --git a/marvell/services/audio/libacm/acm/src/acm_pianosa.c b/marvell/services/audio/libacm/acm/src/acm_pianosa.c
new file mode 100644
index 0000000..357f3c5
--- /dev/null
+++ b/marvell/services/audio/libacm/acm/src/acm_pianosa.c
@@ -0,0 +1,187 @@
+/*
+* 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_ach_pianosa"
+#define LOG_NDEBUG 0
+
+#include <cutils/log.h>
+#include "acm_pianosa.h"
+
+extern int codec_reg_num;
+
+static void PMIC_Enable(void);
+static void PMIC_Disable(void);
+static void PMIC_Reset(void);
+static void PMIC_GetTypeAndID(int *type, unsigned char *id);
+static ACH_ReturnCode PMIC_Handle(void *setting);
+
+ACH_ComponentHandler PMIC_handler = {
+    COMPONENT_INACTIVE,
+    0,
+    PMIC_Enable,
+    PMIC_Disable,
+    PMIC_Reset,
+    PMIC_GetTypeAndID,
+    PMIC_Handle,
+};
+
+extern void I2CWrite(unsigned char numid, unsigned short value);
+extern void I2CRead(unsigned char numid, unsigned char *value);
+
+static void PMIC_RegSet(unsigned char numid, unsigned char value) {
+#ifndef DEBUG_FAKE_ACH
+    I2CWrite(numid, value);
+#endif
+}
+
+void PMIC_RegGet(unsigned char numid, unsigned char *value) {
+#ifndef DEBUG_FAKE_ACH
+    I2CRead(numid, value);
+#endif
+}
+
+static void PMIC_ResetRegCache() {
+    int size = sizeof(reg_cache) / sizeof(reg_cache[0]);
+    int i = 0;
+
+    for (i = 0; i < size; i++) {
+        reg_cache[i].reg_value = reg_cache[i].reg_default;
+    }
+}
+
+unsigned char PMIC_GetRegNumId(unsigned char reg_index) {
+    unsigned char i = 0;
+
+    for (i = 0; i < NUM_OF_REGS; i++) {
+        if (reg_cache[i].reg_index == reg_index) {
+            return codec_reg_num + i;
+        }
+    }
+
+    return 0;
+}
+
+//--------------------------------------------------------------
+//-------- External ACH APIs
+//--------------------------------------------------------------
+static void PMIC_Enable(void) {
+    LOGI(PMIC_Enable, "%s: enable pianosa component", __FUNCTION__);
+}
+
+static void PMIC_Disable(void) {
+    LOGI(PMIC_Disable, "%s: disable pianosa component", __FUNCTION__);
+}
+
+static void PMIC_Reset(void) {
+    LOGI(PMIC_Reset, "%s: Reset pianosa registers!", __FUNCTION__);
+    int size = sizeof(reg_cache) / sizeof(reg_cache[0]);
+    int size_col = sizeof(reg_cache[0]) / sizeof(unsigned char);
+    int i, k = 0;
+    int m;
+    unsigned char j, numid, value, cache_idx;
+    Pianosa_RegisterCache reg_cache_inorder[size];
+
+    for (j = 0x0; j <= 0xff; j++){
+        if (k == size){
+            LOGI(PMIC_Reset1, "%s: copy completed !", __FUNCTION__);
+            break;
+        }
+
+        for (i = 0; i < size; i++) {
+            if (reg_cache[i].reg_prior == j) {
+                memcpy(&reg_cache_inorder[k], &reg_cache[i], size_col);
+                k++;
+            }
+        }
+    }
+
+    for (k = 0; k < size; k++) {
+        if (reg_cache_inorder[k].reg_prior == 0x0) {
+            continue;
+        } else {
+            break;
+        }
+    }
+
+    for (; k < size; k++) {
+        numid = PMIC_GetRegNumId(reg_cache_inorder[k].reg_index);
+        if (numid == 0) {
+            LOGW(PMIC_Reset2, "%s: Invalid numid = %02d!", __FUNCTION__, numid);
+            continue;
+        }
+
+        value = reg_cache_inorder[k].reg_default;
+        cache_idx = numid - codec_reg_num;
+        if (cache_idx < size)
+            reg_cache[cache_idx].reg_value = value;
+        PMIC_RegSet(numid, value);
+#ifdef DEBUG_PMIC
+        LOGI(PMIC_Reset3, "%s: resets pianosa register 0x%02x to value --> 0x%02x",
+            __FUNCTION__,
+            reg_cache_inorder[k].reg_index,
+            value);
+#endif
+    }
+}
+
+static void PMIC_GetTypeAndID(int *type, unsigned char *id){
+    LOGI(PMIC_GetTypeAndID, "%s: Get type and ID for pianosa component", __FUNCTION__);
+    *type = COMPONENT_TYPE_POWER;
+    PMIC_RegGet(PIANOSA_ID_REG, id);
+}
+
+static ACH_ReturnCode PMIC_Handle(void *setting) {
+    ACH_ComponentParameter *param = (ACH_ComponentParameter *)setting;
+    unsigned short i = 0;
+    unsigned char numid, value, cache_idx;
+
+    if (param && param->i2c.reg_value) {
+        numid = PMIC_GetRegNumId(param->i2c.reg_index);
+        if (numid > 0) {
+            //compare with register cache
+            cache_idx = numid - codec_reg_num;
+            value = (reg_cache[cache_idx].reg_value & ~param->i2c.reg_mask) | (*param->i2c.reg_value);
+            if ((reg_cache[cache_idx].reg_value & param->i2c.reg_mask) != (*param->i2c.reg_value)) {
+#ifdef DEBUG_PMIC
+                LOGI(PMIC_Handle, "%s: set register 0x%02x [0x%02x --> 0x%02x]",
+                    __FUNCTION__,
+                    param->i2c.reg_index,
+                    reg_cache[cache_idx].reg_value,
+                    value);
+#endif
+                reg_cache[cache_idx].reg_value = value;
+                PMIC_RegSet(numid, reg_cache[cache_idx].reg_value);
+            } else {
+#ifdef DEBUG_PMIC
+                LOGI(PMIC_Handle1, "%s: set register 0x%02x [0x%02x --> 0x%02x] (unchanged)",
+                    __FUNCTION__,
+                    param->i2c.reg_index,
+                    reg_cache[cache_idx].reg_value,
+                    reg_cache[cache_idx].reg_value);
+#endif
+            }
+        }
+    }
+
+    return ACH_RC_OK;
+}
diff --git a/marvell/services/audio/libacm/acm/src/acm_pm805.h b/marvell/services/audio/libacm/acm/src/acm_pm805.h
new file mode 100644
index 0000000..9387907
--- /dev/null
+++ b/marvell/services/audio/libacm/acm/src/acm_pm805.h
@@ -0,0 +1,224 @@
+/*
+ * ASR Audio path definition of PM805
+ *
+ * Copyright (C) 2018 ASR Microelectronic Ltd.
+ *
+ * Author: Jackie Fan <yuanchunfan@asrmicro.com>
+ *
+ * This file contains proprietary information.
+ * No dissemination allowed without prior written permission from
+ * ASR Microelectronic Ltd.
+ *
+ * File Description:
+ *
+ * This file contains header for audio path definition of PM805
+ */
+
+#ifndef ACM_PM805_H
+#define ACM_PM805_H
+/*
+ * CODEC_PM805: Audio use SAI1
+ */
+#define CODEC_PM805_AUDIO_REG30         0x30
+#define CODEC_PM805_AUDIO_MASTER        0x0f   //16bits, one bit shift, master
+#define CODEC_PM805_AUDIO_SLAVE         0x0e   //16bits, one bit shift, slave
+
+#define CODEC_PM805_AUDIO_REG31         0x31
+#define CODEC_PM805_AUDIO_44100         0x49   //HiFi  use SAI1: 44.1KHz,32fs
+#define CODEC_PM805_AUDIO_8000          0x01   //HiFi  use SAI1: 8KHz,32fs
+#define CODEC_PM805_AUDIO_16000         0x21   //HiFi  use SAI1: 16KHz,32fs
+
+/*
+ * CODEC_PM805: Voice use SAI2
+ */
+#define CODEC_PM805_VOICE_REG35         0x35
+#define CODEC_PM805_VOICE_MASTER        0x0d   //16bits, one bit shift, master
+#define CODEC_PM805_VOICE_SLAVE         0x0c   //16bits, one bit shift, slave
+
+
+#define CODEC_PM805_VOICE_REG36         0x36
+#define CODEC_PM805_VOICE_WB            0xa1   //16KHz,32fs
+#define CODEC_PM805_VOICE_NB            0x81   //8KHz,32fs
+
+//////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////
+/////////////////////////APH_PATH_ID_HIFIPLAYTOEARPHONE//////////////////////////
+ACMAPH_Register ACM_HiFiPlayToEarphone_Disable[]={
+    {ELBA, 0x29, 0x00},{ELBA, 0x90, 0x00},{ELBA, 0x30, 0x0},{ELBA, 0x31, 0x0},{ELBA, 0x32, 0x0},{ELBA, 0x52, 0x00},{ELBA, 0x51, 0x00},
+    {ELBA, 0x50, 0},{ELBA, 0x55, 0x0}
+};
+ACMAPH_Register ACM_HiFiPlayToEarphone_Enable[]={
+    {ELBA, 0x90, 0x7e},{ELBA, 0x30, 0xf},{ELBA, 0x31, CODEC_PM805_AUDIO_44100},{ELBA, 0x32, 0xb},{ELBA, 0x52, 0x00},{ELBA, 0x51, 0x15},
+    {ELBA, 0x50, 0xf},{ELBA, 0x55, 0x20},{ELBA, 0x29, 0xb},{ELBA, 0x56, 0xb4}
+};
+
+/////////////////////////APH_PATH_ID_HIFIPLAYTOSPKR//////////////////////////
+//NOTE:The LINE_P and LINE_N of SPKR are connected with EAR_P and EAR_N, so the register configuration is identical with EarPhone.
+//use the following config in fact.
+ACMAPH_Register ACM_HiFiPlayToSPKR_Disable[]={
+    {ELBA, 0x20, 0},{ELBA, 0x21, 0},{ELBA, 0x53, 0x0},{ELBA, 0x30, 0},{ELBA, 0x31, 0},{ELBA, 0x32, 0},
+    {ELBA, 0x51, 0},{ELBA, 0x50, 0},{ELBA, 0x55, 0x0}
+};
+ACMAPH_Register ACM_HiFiPlayToSPKR_Enable[]={
+    {ELBA, 0x31, CODEC_PM805_AUDIO_44100},{ELBA, 0x30, 0xf},{ELBA, 0x32, 0xb},{ELBA, 0x51, 0x15},{ELBA, 0x55, 0x20},{ELBA, 0x58, 0xb7},
+    {ELBA, 0x50, 0xf},{ELBA, 0x53, 0x00},{ELBA, 0x21, 0x40},{ELBA, 0x20, 0xc1}
+};
+
+/////////////////////////APH_PATH_ID_HIFIPLAYTOHP//////////////////////////
+ACMAPH_Register ACM_HiFiPlayToHP_Disable[]={
+    {ELBA, 0x90, 0},{ELBA, 0x26, 0},{ELBA, 0x30, 0},{ELBA, 0x31, 0},{ELBA, 0x32, 0},
+    {ELBA, 0x52, 0x00},{ELBA, 0x51, 0},{ELBA, 0x50, 0},{ELBA, 0x55, 0}
+};
+ACMAPH_Register ACM_HiFiPlayToHP_Enable[]={
+    {ELBA, 0x28, 0x0},{ELBA, 0x90, 0x7e},{ELBA, 0x30, 0xf},{ELBA, 0x31, CODEC_PM805_AUDIO_44100},{ELBA, 0x32, 0xb},{ELBA, 0x52, 0x00},{ELBA, 0x51, 0x15},
+    {ELBA, 0x50, 0xf},{ELBA, 0x55, 0x20},{ELBA, 0x56, 0x9b},{ELBA, 0x57, 0x9b},{ELBA, 0x26, 0x2b}
+};
+
+/////////////////////////APH_PATH_ID_HIFIRECORDFROMMIC1//////////////////////////
+ACMAPH_Register ACM_HiFiRecordFromMic1_Disable[]={
+    {ELBA, 0x51, 0},{ELBA, 0x16, 0},{ELBA, 0x10, 0x14},{ELBA, 0x11, 0},{ELBA, 0x92, 0},{ELBA, 0x94, 0x3},{ELBA, 0x30, 0},
+    {ELBA, 0x31, 0x0},{ELBA, 0x32, 0x0},{ELBA, 0x50, 0},{ELBA, 0x3c, 0},
+};
+ACMAPH_Register ACM_HiFiRecordFromMic1_Enable[]={
+    {ELBA, 0x11, 0x00},{ELBA, 0x12, 0x14},{ELBA, 0x16, 0x1},{ELBA, 0x10, 0x14},{ELBA, 0x92, 0x56},{ELBA, 0x94, 0x3},{ELBA, 0x30, 0xf},{ELBA, 0x31, CODEC_PM805_AUDIO_44100},
+    {ELBA, 0x32, 0x0b},{ELBA, 0x3c, 0},{ELBA, 0x50, 0xf},{ELBA, 0x51, 0x15}
+};
+ACMAPH_Register ACM_HiFiRecordFromMic1_Mute[]={
+    {ELBA, 0x11, 0x03},
+};
+ACMAPH_Register ACM_HiFiRecordFromMic1_UnMute[]={
+    {ELBA, 0x11, 0x00},
+};
+/////////////////////////APH_PATH_ID_HIFIRECORDFROMHSMIC//////////////////////////
+ACMAPH_Register ACM_HiFiRecordFromHsMic_Disable[]={
+    {ELBA, 0x51, 0},{ELBA, 0x16, 0},{ELBA, 0x10, 0x14},{ELBA, 0x11, 0},{ELBA, 0x92, 0},{ELBA, 0x94, 0x2},{ELBA, 0x30, 0},
+    {ELBA, 0x31, 0x0},{ELBA, 0x32, 0x0},{ELBA, 0x50, 0},{ELBA, 0x3c, 0}
+};
+ACMAPH_Register ACM_HiFiRecordFromHsMic_Enable[]={
+    {ELBA, 0x11, 0x01},{ELBA, 0x12, 0x14},{ELBA, 0x16, 0x9},{ELBA, 0x10, 0x14},{ELBA, 0x92, 0x56},{ELBA, 0x94, 0x1},{ELBA, 0x30, 0xf},{ELBA, 0x31, CODEC_PM805_AUDIO_44100},
+    {ELBA, 0x32, 0x0b},{ELBA, 0x3c, 0},{ELBA, 0x50, 0xf},{ELBA, 0x51, 0x15},
+};
+ACMAPH_Register ACM_HiFiRecordFromHsMic_Mute[]={
+    {ELBA, 0x11, 0x02},
+};
+ACMAPH_Register ACM_HiFiRecordFromHsMic_UnMute[]={
+    {ELBA, 0x11, 0x01},
+};
+//////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////
+/////////////////////////APH_PATH_ID_VOICEPLAYTOEARPHONE//////////////////////////
+
+ACMAPH_Register ACM_VoicePlayToEarphone_Disable[]={
+    {ELBA, 0x29, 0},{ELBA, 0x90, 0x7e},{ELBA, 0x35, 0},{ELBA, 0x36, 0},{ELBA, 0x37, 0},{ELBA, 0x38, 0},{ELBA, 0x39, 0},
+    {ELBA, 0x52, 0x22},{ELBA, 0x51, 0},{ELBA, 0x50, 0},{ELBA, 0x55, 0x0}
+};
+ACMAPH_Register ACM_VoicePlayToEarphone_Enable[]={
+    {ELBA, 0x90, 0x7e},{ELBA, 0x35, CODEC_PM805_VOICE_MASTER},{ELBA, 0x36, CODEC_PM805_VOICE_WB},{ELBA, 0x37, 0x2},{ELBA, 0x38, 0x00},{ELBA, 0x39, 0x10},{ELBA, 0x52, 0x22},
+    {ELBA, 0x51, 0x2a},{ELBA, 0x50, 0xf},{ELBA, 0x55, 0x20},{ELBA, 0x29, 0x0b},{ELBA, 0x56, 0xc7},{ELBA, 0x57, 0xc7}
+};
+
+/////////////////////////APH_PATH_ID_VOICEPLAYTOSPKR//////////////////////////
+//NOTE:The LINE_P and LINE_N of SPKR are connected with EAR_P and EAR_N, so the register configuration is identical with EarPhone.
+//use the following config in fact.
+ACMAPH_Register ACM_VoicePlayToSPKR_Disable[]={
+    {ELBA, 0x53, 0},{ELBA, 0x20, 0},{ELBA, 0x21, 0},{ELBA, 0x90, 0x7e},{ELBA, 0x35, 0},{ELBA, 0x36, 0},{ELBA, 0x37, 0},
+    {ELBA, 0x51, 0},{ELBA, 0x50, 0},{ELBA, 0x55, 0x0}
+};
+ACMAPH_Register ACM_VoicePlayToSPKR_Enable[]={
+    {ELBA, 0x90, 0x7e},{ELBA, 0x35, CODEC_PM805_VOICE_MASTER},{ELBA, 0x36, CODEC_PM805_VOICE_WB},{ELBA, 0x37, 0x2},{ELBA, 0x38, 0x0},{ELBA, 0x39, 0x10},{ELBA, 0x53, 0x20},
+    {ELBA, 0x51, 0x2a},{ELBA, 0x50, 0xf},{ELBA, 0x55, 0x20},{ELBA, 0x21, 0x40},{ELBA, 0x20, 0xc1},{ELBA, 0x58, 0x97}
+};
+
+/////////////////////////APH_PATH_ID_VOICEPLAYTOHP//////////////////////////
+ACMAPH_Register ACM_VoicePlayToHP_Disable[]={
+    {ELBA, 0x26, 0},{ELBA, 0x90, 0x7e},{ELBA, 0x35, 0},{ELBA, 0x36, 0},{ELBA, 0x37, 0},{ELBA, 0x38, 0},{ELBA, 0x39, 0},
+    {ELBA, 0x52, 0x22},{ELBA, 0x51, 0},{ELBA, 0x50, 0},{ELBA, 0x55, 0}
+};
+ACMAPH_Register ACM_VoicePlayToHP_Enable[]={
+    {ELBA, 0x28, 0x0},{ELBA, 0x90, 0x7e},{ELBA, 0x35, CODEC_PM805_VOICE_MASTER},{ELBA, 0x36, CODEC_PM805_VOICE_WB},{ELBA, 0x37, 0x2},{ELBA, 0x38, 0},{ELBA, 0x39, 0},{ELBA, 0x52, 0x22},
+    {ELBA, 0x50, 0xf},{ELBA, 0x55, 0x20},{ELBA, 0x26, 0x2b},{ELBA, 0x56, 0x9b},{ELBA, 0x57, 0x9b},{ELBA, 0x51, 0x2a},
+};
+
+/////////////////////////APH_PATH_ID_VOICERECORDFROMMIC1//////////////////////////
+ACMAPH_Register ACM_VoiceRecordFromMic1_Disable[]={
+    {ELBA, 0x12, 0},{ELBA, 0x51, 0},{ELBA, 0x16, 0},{ELBA, 0x92, 0},{ELBA, 0x94, 0x2},{ELBA, 0x10, 0x14},{ELBA, 0x11, 0},{ELBA, 0x3d, 0x1},
+    {ELBA, 0x50, 0},{ELBA, 0x35, 0},{ELBA, 0x36, 0},{ELBA, 0x37, 0}, {ELBA, 0x38, 0},
+};
+ACMAPH_Register ACM_VoiceRecordFromMic1_Enable[]={
+    {ELBA, 0x11, 0x00},{ELBA, 0x16, 0x1},{ELBA, 0x92, 0x56},{ELBA, 0x94, 0x1},{ELBA, 0x10, 0x14},{ELBA, 0x35, CODEC_PM805_VOICE_MASTER},{ELBA, 0x36, CODEC_PM805_VOICE_WB},
+    {ELBA, 0x37, 0x2},{ELBA, 0x38, 0},{ELBA, 0x3d, 0x1},{ELBA, 0x50, 0xf},{ELBA, 0x51, 0x2a}
+};
+ACMAPH_Register ACM_VoiceRecordFromMic1_Mute[]={
+    {ELBA, 0x11, 0x3},
+};
+ACMAPH_Register ACM_VoiceRecordFromMic1_UnMute[]={
+    {ELBA, 0x11, 0x00},
+};
+/////////////////////////APH_PATH_ID_VOICERECORDFROMHSMIC//////////////////////////
+ACMAPH_Register ACM_VoiceRecordFromHsMic_Disable[]={
+    {ELBA, 0x51, 0},{ELBA, 0x16, 0},{ELBA, 0x10, 0x14},{ELBA, 0x11, 0},{ELBA, 0x92, 0},{ELBA, 0x94, 0x2},{ELBA, 0x3d, 1},
+    {ELBA, 0x50, 0},{ELBA, 0x35, 0},{ELBA, 0x36, 0},{ELBA, 0x37, 0},{ELBA, 0x38, 0}
+};
+ACMAPH_Register ACM_VoiceRecordFromHsMic_Enable[]={
+    {ELBA, 0x11, 0x01},{ELBA, 0x16, 0x49},{ELBA, 0x10, 0x14},{ELBA, 0x92, 0x56},{ELBA, 0x94, 0x1},{ELBA, 0x35, CODEC_PM805_VOICE_MASTER},{ELBA, 0x36, CODEC_PM805_VOICE_WB},
+    {ELBA, 0x37, 0x02},{ELBA, 0x38, 0},{ELBA, 0x3d, 1},{ELBA, 0x50, 0xf},{ELBA, 0x51, 0x2a},{ELBA, 0x12, 0x0}
+};
+ACMAPH_Register ACM_VoiceRecordFromHsMic_Mute[]={
+    {ELBA, 0x11, 0x2},
+};
+ACMAPH_Register ACM_VoiceRecordFromHsMic_UnMute[]={
+    {ELBA, 0x11, 0x01},
+};
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+static ACMAPH_Component ACM_Disable[APH_PATH_ID_CNT]={
+    {APH_PATH_ID_HIFIPLAYTOEARPHONE,    ACM_HiFiPlayToEarphone_Disable,     sizeof(ACM_HiFiPlayToEarphone_Disable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIPLAYTOSPKR,        ACM_HiFiPlayToSPKR_Disable,         sizeof(ACM_HiFiPlayToSPKR_Disable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIPLAYTOHP,          ACM_HiFiPlayToHP_Disable,           sizeof(ACM_HiFiPlayToHP_Disable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIRECORDFROMMIC1,    ACM_HiFiRecordFromMic1_Disable,     sizeof(ACM_HiFiRecordFromMic1_Disable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIRECORDFROMHSMIC,   ACM_HiFiRecordFromHsMic_Disable,    sizeof(ACM_HiFiRecordFromHsMic_Disable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICEPLAYTOEARPHONE,   ACM_VoicePlayToEarphone_Disable,    sizeof(ACM_VoicePlayToEarphone_Disable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICEPLAYTOSPKR,       ACM_VoicePlayToSPKR_Disable,        sizeof(ACM_VoicePlayToSPKR_Disable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICEPLAYTOHP,         ACM_VoicePlayToHP_Disable,          sizeof(ACM_VoicePlayToHP_Disable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICERECORDFROMMIC1,   ACM_VoiceRecordFromMic1_Disable,    sizeof(ACM_VoiceRecordFromMic1_Disable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICERECORDFROMHSMIC,  ACM_VoiceRecordFromHsMic_Disable,   sizeof(ACM_VoiceRecordFromHsMic_Disable)/sizeof(ACMAPH_Register)},
+};
+
+static ACMAPH_Component ACM_Enable[APH_PATH_ID_CNT]={
+    {APH_PATH_ID_HIFIPLAYTOEARPHONE,    ACM_HiFiPlayToEarphone_Enable,      sizeof(ACM_HiFiPlayToEarphone_Enable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIPLAYTOSPKR,        ACM_HiFiPlayToSPKR_Enable,          sizeof(ACM_HiFiPlayToSPKR_Enable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIPLAYTOHP,          ACM_HiFiPlayToHP_Enable,            sizeof(ACM_HiFiPlayToHP_Enable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIRECORDFROMMIC1,    ACM_HiFiRecordFromMic1_Enable,      sizeof(ACM_HiFiRecordFromMic1_Enable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIRECORDFROMHSMIC,   ACM_HiFiRecordFromHsMic_Enable,     sizeof(ACM_HiFiRecordFromHsMic_Enable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICEPLAYTOEARPHONE,   ACM_VoicePlayToEarphone_Enable,     sizeof(ACM_VoicePlayToEarphone_Enable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICEPLAYTOSPKR,       ACM_VoicePlayToSPKR_Enable,         sizeof(ACM_VoicePlayToSPKR_Enable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICEPLAYTOHP,         ACM_VoicePlayToHP_Enable,           sizeof(ACM_VoicePlayToHP_Enable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICERECORDFROMMIC1,   ACM_VoiceRecordFromMic1_Enable,     sizeof(ACM_VoiceRecordFromMic1_Enable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICERECORDFROMHSMIC,  ACM_VoiceRecordFromHsMic_Enable,    sizeof(ACM_VoiceRecordFromHsMic_Enable)/sizeof(ACMAPH_Register)},
+};
+
+static ACMAPH_Component ACM_Mute[APH_PATH_IN_CNT]={
+    {APH_PATH_ID_HIFIRECORDFROMMIC1,    ACM_HiFiRecordFromMic1_Mute,      sizeof(ACM_HiFiRecordFromMic1_Mute)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIRECORDFROMHSMIC,   ACM_HiFiRecordFromHsMic_Mute,     sizeof(ACM_HiFiRecordFromHsMic_Mute)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICERECORDFROMMIC1,   ACM_VoiceRecordFromMic1_Mute,     sizeof(ACM_VoiceRecordFromMic1_Mute)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICERECORDFROMHSMIC,  ACM_VoiceRecordFromHsMic_Mute,    sizeof(ACM_VoiceRecordFromHsMic_Mute)/sizeof(ACMAPH_Register)},
+};
+static ACMAPH_Component ACM_UnMute[APH_PATH_IN_CNT]={
+    {APH_PATH_ID_HIFIRECORDFROMMIC1,    ACM_HiFiRecordFromMic1_UnMute,      sizeof(ACM_HiFiRecordFromMic1_UnMute)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIRECORDFROMHSMIC,   ACM_HiFiRecordFromHsMic_UnMute,     sizeof(ACM_HiFiRecordFromHsMic_UnMute)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICERECORDFROMMIC1,   ACM_VoiceRecordFromMic1_UnMute,     sizeof(ACM_VoiceRecordFromMic1_UnMute)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICERECORDFROMHSMIC,  ACM_VoiceRecordFromHsMic_UnMute,    sizeof(ACM_VoiceRecordFromHsMic_UnMute)/sizeof(ACMAPH_Register)},
+};
+
+extern ACH_ComponentHandler elba_handler;
+extern ACH_ComponentHandler ustica_handler;
+
+static APH_ACHComponent ACH_component_table[] = {
+    {ELBA, &elba_handler},
+};
+//Sorted as APH_AudioComponent
+static char APH_AudioComponent_Name[][16]= {
+    "ELBA",
+} ;
+
+#endif
diff --git a/marvell/services/audio/libacm/acm/src/acm_pm812.h b/marvell/services/audio/libacm/acm/src/acm_pm812.h
new file mode 100644
index 0000000..b20c651
--- /dev/null
+++ b/marvell/services/audio/libacm/acm/src/acm_pm812.h
@@ -0,0 +1,215 @@
+/*
+ * ASR Audio path definition of PM812
+ *
+ * Copyright (C) 2018 ASR Microelectronic Ltd.
+ *
+ * Author: Jackie Fan <yuanchunfan@asrmicro.com>
+ *
+ * This file contains proprietary information.
+ * No dissemination allowed without prior written permission from
+ * ASR Microelectronic Ltd.
+ *
+ * File Description:
+ *
+ * This file contains header for audio path definition of PM812
+ */
+
+#ifndef ACM_PM812_H
+#define ACM_PM812_H
+/*
+ * CODEC_PM812: Audio use SAI1
+ */
+#define SAI1_REG31_VALUE 0x49   //HiFi  use SAI1: 44.1KHz,32fs
+
+/*
+ * CODEC_PM812: Voice use SAI2
+ */
+#define CODEC_PM812_VOICE_REG35         0x35
+#define CODEC_PM812_VOICE_MASTER        0x0d   //16bits, one bit shift, master
+#define CODEC_PM812_VOICE_SLAVE         0x0c   //16bits, one bit shift, slave
+
+
+#define CODEC_PM812_VOICE_REG36         0x36
+#define CODEC_PM812_VOICE_WB            0xa1   //16KHz,32fs
+#define CODEC_PM812_VOICE_NB            0x81   //8KHz,32fs
+
+//////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////
+/////////////////////////APH_PATH_ID_HIFIPLAYTOEARPHONE//////////////////////////
+ACMAPH_Register ACM_HiFiPlayToEarphone_Disable[]={
+    {ELBA, 0x29, 0x00},{ELBA, 0x90, 0x00},{ELBA, 0x30, 0x0},{ELBA, 0x31, SAI1_REG31_VALUE},{ELBA, 0x32, 0x0},{ELBA, 0x52, 0x00},{ELBA, 0x51, 0x15},
+    {ELBA, 0x50, 0},{ELBA, 0x55, 0x0}
+};
+ACMAPH_Register ACM_HiFiPlayToEarphone_Enable[]={
+    {ELBA, 0x90, 0x7e},{ELBA, 0x30, 0xf},{ELBA, 0x31, SAI1_REG31_VALUE},{ELBA, 0x32, 0x4},{ELBA, 0x52, 0x00},{ELBA, 0x51, 0x15},
+    {ELBA, 0x50, 0xf},{ELBA, 0x55, 0x20},{ELBA, 0x29, 0xb},{ELBA, 0x56, 0xb4}
+};
+
+/////////////////////////APH_PATH_ID_HIFIPLAYTOSPKR//////////////////////////
+ACMAPH_Register ACM_HiFiPlayToSPKR_Disable[]={
+    {ELBA, 0x20, 0},{ELBA, 0x21, 0},{ELBA, 0x53, 0x0},{ELBA, 0x30, 0},{ELBA, 0x31, 0},{ELBA, 0x32, 0},
+    {ELBA, 0x51, 0},{ELBA, 0x50, 0},{ELBA, 0x55, 0x0},{USTICA, 0x48, 0x0},{USTICA, 0x4a, 0x70},{USTICA, 0x4b, 0x0}
+};
+ACMAPH_Register ACM_HiFiPlayToSPKR_Enable[]={
+    {ELBA, 0x31, SAI1_REG31_VALUE},{ELBA, 0x30, 0xf},{ELBA, 0x32, 0x4},{ELBA, 0x51, 0x15},{ELBA, 0x55, 0x20},{ELBA, 0x58, 0xb7},
+    {ELBA, 0x50, 0xf},{ELBA, 0x53, 0x00},{ELBA, 0x21, 0x40},{ELBA, 0x20, 0xc1},{USTICA, 0x48, 0xe0},{USTICA, 0x4a, 0x70},{USTICA, 0x4b, 0x7}
+};
+
+/////////////////////////APH_PATH_ID_HIFIPLAYTOHP//////////////////////////
+ACMAPH_Register ACM_HiFiPlayToHP_Disable[]={
+    {ELBA, 0x90, 0},{ELBA, 0x26, 0},{ELBA, 0x30, 0},{ELBA, 0x31, 0},{ELBA, 0x32, 0},
+    {ELBA, 0x52, 0x00},{ELBA, 0x51, 0},{ELBA, 0x50, 0},{ELBA, 0x55, 0}
+};
+ACMAPH_Register ACM_HiFiPlayToHP_Enable[]={
+    {ELBA, 0x28, 0x0},{ELBA, 0x90, 0x7e},{ELBA, 0x30, 0xf},{ELBA, 0x31, SAI1_REG31_VALUE},{ELBA, 0x32, 0x4},{ELBA, 0x52, 0x00},{ELBA, 0x51, 0x15},
+    {ELBA, 0x50, 0xf},{ELBA, 0x55, 0x20},{ELBA, 0x56, 0x9b},{ELBA, 0x57, 0x9b},{ELBA, 0x26, 0x2b}
+};
+
+/////////////////////////APH_PATH_ID_HIFIRECORDFROMMIC1//////////////////////////
+ACMAPH_Register ACM_HiFiRecordFromMic1_Disable[]={
+    {ELBA, 0x51, 0},{ELBA, 0x16, 0},{ELBA, 0x10, 0x14},{ELBA, 0x11, 0},{ELBA, 0x92, 0},{ELBA, 0x94, 0x3},{ELBA, 0x30, 0},
+    {ELBA, 0x31, SAI1_REG31_VALUE},{ELBA, 0x32, 0x0},{ELBA, 0x50, 0},{ELBA, 0x3c, 0}
+};
+ACMAPH_Register ACM_HiFiRecordFromMic1_Enable[]={
+    {ELBA, 0x11, 0x00},{ELBA, 0x12, 0x14},{ELBA, 0x16, 0x1},{ELBA, 0x10, 0x14},{ELBA, 0x92, 0x56},{ELBA, 0x94, 0x3},{ELBA, 0x30, 0xf},{ELBA, 0x31, SAI1_REG31_VALUE},
+    {ELBA, 0x32, 0x04},{ELBA, 0x3c, 0},{ELBA, 0x50, 0xf},{ELBA, 0x51, 0x15},
+};
+ACMAPH_Register ACM_HiFiRecordFromMic1_Mute[]={
+    {ELBA, 0x11, 0x03},
+};
+ACMAPH_Register ACM_HiFiRecordFromMic1_UnMute[]={
+    {ELBA, 0x11, 0x00},
+};
+/////////////////////////APH_PATH_ID_HIFIRECORDFROMHSMIC//////////////////////////
+ACMAPH_Register ACM_HiFiRecordFromHsMic_Disable[]={
+    {ELBA, 0x51, 0},{ELBA, 0x16, 0},{ELBA, 0x10, 0x14},{ELBA, 0x11, 0},{ELBA, 0x92, 0},{ELBA, 0x94, 0x2},{ELBA, 0x30, 0},
+    {ELBA, 0x31, SAI1_REG31_VALUE},{ELBA, 0x32, 0x0},{ELBA, 0x50, 0},{ELBA, 0x3c, 0}
+};
+ACMAPH_Register ACM_HiFiRecordFromHsMic_Enable[]={
+    {ELBA, 0x11, 0x01},{ELBA, 0x12, 0x14},{ELBA, 0x16, 0x9},{ELBA, 0x10, 0x14},{ELBA, 0x92, 0x56},{ELBA, 0x94, 0x1},{ELBA, 0x30, 0xf},{ELBA, 0x31, SAI1_REG31_VALUE},
+    {ELBA, 0x32, 0x04},{ELBA, 0x3c, 0},{ELBA, 0x50, 0xf},{ELBA, 0x51, 0x15},
+};
+ACMAPH_Register ACM_HiFiRecordFromHsMic_Mute[]={
+    {ELBA, 0x11, 0x02},
+};
+ACMAPH_Register ACM_HiFiRecordFromHsMic_UnMute[]={
+    {ELBA, 0x11, 0x01},
+};
+//////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////
+/////////////////////////APH_PATH_ID_VOICEPLAYTOEARPHONE//////////////////////////
+
+ACMAPH_Register ACM_VoicePlayToEarphone_Disable[]={
+    {ELBA, 0x29, 0},{ELBA, 0x90, 0x7e},{ELBA, 0x35, 0},{ELBA, 0x36, 0},{ELBA, 0x37, 0},{ELBA, 0x38, 0},{ELBA, 0x39, 0},
+    {ELBA, 0x52, 0x22},{ELBA, 0x51, 0},{ELBA, 0x50, 0},{ELBA, 0x55, 0x0}
+};
+ACMAPH_Register ACM_VoicePlayToEarphone_Enable[]={
+    {ELBA, 0x90, 0x7e},{ELBA, 0x35, CODEC_PM812_VOICE_MASTER},{ELBA, 0x36, CODEC_PM812_VOICE_WB},{ELBA, 0x37, 0x2},{ELBA, 0x38, 0x00},{ELBA, 0x39, 0x10},{ELBA, 0x52, 0x22},
+    {ELBA, 0x51, 0x2a},{ELBA, 0x50, 0xf},{ELBA, 0x55, 0x20},{ELBA, 0x29, 0x0b},{ELBA, 0x56, 0xb7}
+};
+
+/////////////////////////APH_PATH_ID_VOICEPLAYTOSPKR//////////////////////////
+ACMAPH_Register ACM_VoicePlayToSPKR_Disable[]={
+    {ELBA, 0x53, 0},{ELBA, 0x20, 0},{ELBA, 0x21, 0},{ELBA, 0x90, 0x7e},{ELBA, 0x35, 0},{ELBA, 0x36, 0},{ELBA, 0x37, 0},
+    {ELBA, 0x51, 0},{ELBA, 0x50, 0},{ELBA, 0x55, 0x0},{USTICA, 0x48, 0},{USTICA, 0x4a, 0x70},{USTICA, 0x4b, 0}
+};
+ACMAPH_Register ACM_VoicePlayToSPKR_Enable[]={
+    {ELBA, 0x90, 0x7e},{ELBA, 0x35, CODEC_PM812_VOICE_MASTER},{ELBA, 0x36, CODEC_PM812_VOICE_WB},{ELBA, 0x37, 0x2},{ELBA, 0x38, 0x0},{ELBA, 0x39, 0x10},{ELBA, 0x53, 0x20},
+    {ELBA, 0x51, 0x2a},{ELBA, 0x50, 0xf},{ELBA, 0x55, 0x20},{ELBA, 0x21, 0x40},{ELBA, 0x20, 0xc1},{ELBA, 0x58, 0x97},{USTICA, 0x48, 0xe0},{USTICA, 0x4a, 0x70},{USTICA, 0x4b, 0x7}
+};
+
+/////////////////////////APH_PATH_ID_VOICEPLAYTOHP//////////////////////////
+ACMAPH_Register ACM_VoicePlayToHP_Disable[]={
+    {ELBA, 0x26, 0},{ELBA, 0x90, 0x7e},{ELBA, 0x35, 0},{ELBA, 0x36, 0},{ELBA, 0x37, 0},{ELBA, 0x38, 0},{ELBA, 0x39, 0},
+    {ELBA, 0x52, 0x22},{ELBA, 0x51, 0},{ELBA, 0x50, 0},{ELBA, 0x55, 0}
+};
+ACMAPH_Register ACM_VoicePlayToHP_Enable[]={
+    {ELBA, 0x28, 0x0},{ELBA, 0x90, 0x7e},{ELBA, 0x35, CODEC_PM812_VOICE_MASTER},{ELBA, 0x36, CODEC_PM812_VOICE_WB},{ELBA, 0x37, 0x2},{ELBA, 0x38, 0},{ELBA, 0x39, 0},{ELBA, 0x52, 0x22},
+    {ELBA, 0x50, 0xf},{ELBA, 0x55, 0x20},{ELBA, 0x26, 0x2b},{ELBA, 0x56, 0x9b},{ELBA, 0x57, 0x9b},{ELBA, 0x51, 0x2a},
+};
+
+/////////////////////////APH_PATH_ID_VOICERECORDFROMMIC1//////////////////////////
+ACMAPH_Register ACM_VoiceRecordFromMic1_Disable[]={
+    {ELBA, 0x12, 0},{ELBA, 0x51, 0},{ELBA, 0x16, 0},{ELBA, 0x92, 0},{ELBA, 0x94, 0x2},{ELBA, 0x10, 0x14},{ELBA, 0x11, 0},{ELBA, 0x3d, 0x1},
+    {ELBA, 0x50, 0},{ELBA, 0x35, 0},{ELBA, 0x36, 0},{ELBA, 0x37, 0}, {ELBA, 0x38, 0},
+};
+ACMAPH_Register ACM_VoiceRecordFromMic1_Enable[]={
+    {ELBA, 0x11, 0x00},{ELBA, 0x16, 0x1},{ELBA, 0x92, 0x56},{ELBA, 0x94, 0x1},{ELBA, 0x10, 0x14},{ELBA, 0x35, CODEC_PM812_VOICE_MASTER},{ELBA, 0x36, CODEC_PM812_VOICE_WB},
+    {ELBA, 0x37, 0x2},{ELBA, 0x38, 0},{ELBA, 0x3d, 0x1},{ELBA, 0x50, 0xf},{ELBA, 0x51, 0x2a}
+};
+ACMAPH_Register ACM_VoiceRecordFromMic1_Mute[]={
+    {ELBA, 0x11, 0x3},
+};
+ACMAPH_Register ACM_VoiceRecordFromMic1_UnMute[]={
+    {ELBA, 0x11, 0x00},
+};
+/////////////////////////APH_PATH_ID_VOICERECORDFROMHSMIC//////////////////////////
+ACMAPH_Register ACM_VoiceRecordFromHsMic_Disable[]={
+    {ELBA, 0x51, 0},{ELBA, 0x16, 0},{ELBA, 0x10, 0x14},{ELBA, 0x11, 0},{ELBA, 0x92, 0},{ELBA, 0x94, 0x2},{ELBA, 0x3d, 1},
+    {ELBA, 0x50, 0},{ELBA, 0x35, 0},{ELBA, 0x36, 0},{ELBA, 0x37, 0},{ELBA, 0x38, 0}
+};
+ACMAPH_Register ACM_VoiceRecordFromHsMic_Enable[]={
+    {ELBA, 0x11, 0x01},{ELBA, 0x16, 0x49},{ELBA, 0x10, 0x14},{ELBA, 0x92, 0x56},{ELBA, 0x94, 0x1},{ELBA, 0x35, CODEC_PM812_VOICE_MASTER},{ELBA, 0x36, CODEC_PM812_VOICE_WB},
+    {ELBA, 0x37, 0x02},{ELBA, 0x38, 0},{ELBA, 0x3d, 1},{ELBA, 0x50, 0xf},{ELBA, 0x51, 0x2a},{ELBA, 0x12, 0x0}
+};
+ACMAPH_Register ACM_VoiceRecordFromHsMic_Mute[]={
+    {ELBA, 0x11, 0x2},
+};
+ACMAPH_Register ACM_VoiceRecordFromHsMic_UnMute[]={
+    {ELBA, 0x11, 0x01},
+};
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+static ACMAPH_Component ACM_Disable[APH_PATH_ID_CNT]={
+    {APH_PATH_ID_HIFIPLAYTOEARPHONE,    ACM_HiFiPlayToEarphone_Disable,     sizeof(ACM_HiFiPlayToEarphone_Disable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIPLAYTOSPKR,        ACM_HiFiPlayToSPKR_Disable,         sizeof(ACM_HiFiPlayToSPKR_Disable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIPLAYTOHP,          ACM_HiFiPlayToHP_Disable,           sizeof(ACM_HiFiPlayToHP_Disable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIRECORDFROMMIC1,    ACM_HiFiRecordFromMic1_Disable,     sizeof(ACM_HiFiRecordFromMic1_Disable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIRECORDFROMHSMIC,   ACM_HiFiRecordFromHsMic_Disable,    sizeof(ACM_HiFiRecordFromHsMic_Disable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICEPLAYTOEARPHONE,   ACM_VoicePlayToEarphone_Disable,    sizeof(ACM_VoicePlayToEarphone_Disable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICEPLAYTOSPKR,       ACM_VoicePlayToSPKR_Disable,        sizeof(ACM_VoicePlayToSPKR_Disable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICEPLAYTOHP,         ACM_VoicePlayToHP_Disable,          sizeof(ACM_VoicePlayToHP_Disable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICERECORDFROMMIC1,   ACM_VoiceRecordFromMic1_Disable,    sizeof(ACM_VoiceRecordFromMic1_Disable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICERECORDFROMHSMIC,  ACM_VoiceRecordFromHsMic_Disable,   sizeof(ACM_VoiceRecordFromHsMic_Disable)/sizeof(ACMAPH_Register)},
+};
+
+static ACMAPH_Component ACM_Enable[APH_PATH_ID_CNT]={
+    {APH_PATH_ID_HIFIPLAYTOEARPHONE,    ACM_HiFiPlayToEarphone_Enable,      sizeof(ACM_HiFiPlayToEarphone_Enable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIPLAYTOSPKR,        ACM_HiFiPlayToSPKR_Enable,          sizeof(ACM_HiFiPlayToSPKR_Enable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIPLAYTOHP,          ACM_HiFiPlayToHP_Enable,            sizeof(ACM_HiFiPlayToHP_Enable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIRECORDFROMMIC1,    ACM_HiFiRecordFromMic1_Enable,      sizeof(ACM_HiFiRecordFromMic1_Enable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIRECORDFROMHSMIC,   ACM_HiFiRecordFromHsMic_Enable,     sizeof(ACM_HiFiRecordFromHsMic_Enable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICEPLAYTOEARPHONE,   ACM_VoicePlayToEarphone_Enable,     sizeof(ACM_VoicePlayToEarphone_Enable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICEPLAYTOSPKR,       ACM_VoicePlayToSPKR_Enable,         sizeof(ACM_VoicePlayToSPKR_Enable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICEPLAYTOHP,         ACM_VoicePlayToHP_Enable,           sizeof(ACM_VoicePlayToHP_Enable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICERECORDFROMMIC1,   ACM_VoiceRecordFromMic1_Enable,     sizeof(ACM_VoiceRecordFromMic1_Enable)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICERECORDFROMHSMIC,  ACM_VoiceRecordFromHsMic_Enable,    sizeof(ACM_VoiceRecordFromHsMic_Enable)/sizeof(ACMAPH_Register)},
+};
+
+static ACMAPH_Component ACM_Mute[APH_PATH_IN_CNT]={
+    {APH_PATH_ID_HIFIRECORDFROMMIC1,    ACM_HiFiRecordFromMic1_Mute,      sizeof(ACM_HiFiRecordFromMic1_Mute)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIRECORDFROMHSMIC,   ACM_HiFiRecordFromHsMic_Mute,     sizeof(ACM_HiFiRecordFromHsMic_Mute)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICERECORDFROMMIC1,   ACM_VoiceRecordFromMic1_Mute,     sizeof(ACM_VoiceRecordFromMic1_Mute)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICERECORDFROMHSMIC,  ACM_VoiceRecordFromHsMic_Mute,    sizeof(ACM_VoiceRecordFromHsMic_Mute)/sizeof(ACMAPH_Register)},
+};
+static ACMAPH_Component ACM_UnMute[APH_PATH_IN_CNT]={
+    {APH_PATH_ID_HIFIRECORDFROMMIC1,    ACM_HiFiRecordFromMic1_UnMute,      sizeof(ACM_HiFiRecordFromMic1_UnMute)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_HIFIRECORDFROMHSMIC,   ACM_HiFiRecordFromHsMic_UnMute,     sizeof(ACM_HiFiRecordFromHsMic_UnMute)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICERECORDFROMMIC1,   ACM_VoiceRecordFromMic1_UnMute,     sizeof(ACM_VoiceRecordFromMic1_UnMute)/sizeof(ACMAPH_Register)},
+    {APH_PATH_ID_VOICERECORDFROMHSMIC,  ACM_VoiceRecordFromHsMic_UnMute,    sizeof(ACM_VoiceRecordFromHsMic_UnMute)/sizeof(ACMAPH_Register)},
+};
+
+extern ACH_ComponentHandler elba_handler;
+extern ACH_ComponentHandler ustica_handler;
+
+static APH_ACHComponent ACH_component_table[] = {
+    {ELBA, &elba_handler},
+    {USTICA, &ustica_handler},
+};
+//Sorted as APH_AudioComponent
+static char APH_AudioComponent_Name[][16]= {
+    "ELBA",
+    "USTICA",
+} ;
+
+#endif
diff --git a/marvell/services/audio/libacm/acm/src/acm_record_mode.c b/marvell/services/audio/libacm/acm/src/acm_record_mode.c
new file mode 100644
index 0000000..4e7dd36
--- /dev/null
+++ b/marvell/services/audio/libacm/acm/src/acm_record_mode.c
@@ -0,0 +1,64 @@
+/*
+ * 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_record_mode"
+#define LOG_NDEBUG 0
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <cutils/log.h>
+
+#define GSSP_RECORD_DEV "/sys/devices/platform/sound/gssp_record"
+
+int is_gssp_record_mode_support(void) {
+    int mDev;
+    int rec_mode = 0;
+    char value[8] = "0";
+    int byte = 0;
+
+    // query gssp record mode
+    mDev = open(GSSP_RECORD_DEV, O_RDWR);
+    if (mDev < 0) {
+        LOGE(is_gssp_record_mode_support, "%s: Failed to open %s\n", __FUNCTION__, GSSP_RECORD_DEV);
+        return 0;
+    } else {
+        LOGI(is_gssp_record_mode_support1, "%s: Open %s\n", __FUNCTION__, GSSP_RECORD_DEV);
+        byte = read(mDev, value, 1);
+        if(byte == -1) {
+            LOGE(is_gssp_record_mode_support2, "%s: Failed to read %s\n", __FUNCTION__, GSSP_RECORD_DEV);
+        }
+        close(mDev);
+        mDev = -1;
+    }
+    rec_mode = atoi(value);
+    if (rec_mode) {
+        LOGV(is_gssp_record_mode_support3, "%s: rec_mode = %d, gssp record mode is supported!\n", __FUNCTION__, rec_mode);
+        return 1;
+    } else {
+        LOGV(is_gssp_record_mode_support4, "%s: rec_mode = %d, gssp record mode is not supported!\n", __FUNCTION__, rec_mode);
+        return 0;
+    }
+}
diff --git a/marvell/services/audio/libacm/acm/src/acm_ustica.c b/marvell/services/audio/libacm/acm/src/acm_ustica.c
new file mode 100644
index 0000000..37170ac
--- /dev/null
+++ b/marvell/services/audio/libacm/acm/src/acm_ustica.c
@@ -0,0 +1,228 @@
+/*
+* 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_ach_ustica"
+#define LOG_NDEBUG 0
+
+#include <cutils/log.h>
+#include "acm_ustica.h"
+
+#ifdef PXA1826_AUDIO
+#ifndef ACM_ALSA_INIT
+#define ACM_ALSA_INIT
+#endif
+#endif
+
+extern int codec_reg_num;
+
+static void Ustica_Enable(void);
+static void Ustica_Disable(void);
+static void Ustica_Reset(void);
+static void Ustica_GetTypeAndID(int *type, unsigned char *id);
+static ACH_ReturnCode Ustica_Handle(void *setting);
+
+ACH_ComponentHandler ustica_handler = {
+    COMPONENT_INACTIVE,
+    0,
+    Ustica_Enable,
+    Ustica_Disable,
+    Ustica_Reset,
+    Ustica_GetTypeAndID,
+    Ustica_Handle,
+};
+
+extern int I2CInit(void);
+extern int I2CDeInit(void);
+extern void I2CWrite(unsigned char numid, unsigned short value);
+extern void I2CRead(unsigned char numid, unsigned char *value);
+
+static void Ustica_RegSet(unsigned char numid, unsigned char value) {
+#ifndef DEBUG_FAKE_ACH
+    I2CWrite(numid, value);
+#else
+	LOGD(Ustica_RegSet, "  FAKE_ACH: %s(0x%x, 0x%x)", __FUNCTION__, numid, value);
+#endif
+}
+
+void Ustica_RegGet(unsigned char numid, unsigned char *value) {
+#ifndef DEBUG_FAKE_ACH
+    I2CRead(numid, value);
+#else
+	LOGD(Ustica_RegGet, "  FAKE_ACH: %s(0x%x, ..)", __FUNCTION__, numid);
+#endif
+}
+
+static void Ustica_ResetRegCache() {
+    int size = sizeof(reg_cache) / sizeof(reg_cache[0]);
+    int i = 0;
+
+    for (i = 0; i < size; i++) {
+        reg_cache[i].reg_value = reg_cache[i].reg_default;
+    }
+}
+
+unsigned char Ustica_GetRegNumId(unsigned char reg_index) {
+    unsigned char i = 0;
+
+    for (i = 0; i < NUM_OF_REGS; i++) {
+        if (reg_cache[i].reg_index == reg_index) {
+            return codec_reg_num + i;
+        }
+    }
+
+    return 0;
+}
+
+//--------------------------------------------------------------
+//-------- External ACH APIs
+//--------------------------------------------------------------
+#ifdef ACM_ALSA_INIT
+// NOTE about pair Enable/Disable
+//  On startup Disable could be called without Enable as Init/Reset sequence
+//  Skip DeInit for first Disable without Enable
+//
+static int _acm_initialized;
+#endif
+
+static void Ustica_Enable(void) {
+    LOGI(Ustica_Enable, "%s: enable ustica component", __FUNCTION__);
+#ifdef ACM_ALSA_INIT
+	_acm_initialized = 1;
+	I2CInit(); //adaptor to alsa-mixer
+#endif
+}
+
+static void Ustica_Disable(void) {
+    LOGI(Ustica_Disable, "%s: disable ustica component", __FUNCTION__);
+#ifdef ACM_ALSA_INIT
+	if (_acm_initialized) {
+		_acm_initialized = 1;
+		I2CDeInit(); //adaptor to alsa-mixer
+	}
+#endif
+}
+
+static void Ustica_Reset(void) {
+    LOGI(Ustica_Reset, "%s: Reset ustica registers!", __FUNCTION__);
+    int size = sizeof(reg_cache) / sizeof(reg_cache[0]);
+    int size_col = sizeof(reg_cache[0]) / sizeof(unsigned char);
+    int i, k = 0;
+    unsigned char j, numid, value, cache_idx;
+    Ustica_RegisterCache reg_cache_inorder[size];
+
+#ifdef ACM_ALSA_INIT
+	I2CInit(); //make sure to enable mixer before and close after this operation
+#endif
+    for (j = 0x0; j <= 0xff; j++){
+        if (k == size){
+            LOGI(Ustica_Reset0, "%s: copy completed !", __FUNCTION__);
+            break;
+        }
+
+        for (i = 0; i < size; i++) {
+            if (reg_cache[i].reg_prior == j) {
+                memcpy(&reg_cache_inorder[k], &reg_cache[i], size_col);
+                k++;
+            }
+        }
+    }
+
+    for (k = 0; k < size; k++) {
+        if (reg_cache_inorder[k].reg_prior == 0x0) {
+            continue;
+        } else {
+            break;
+        }
+    }
+
+    for (; k < size; k++) {
+        numid = Ustica_GetRegNumId(reg_cache_inorder[k].reg_index);
+        if (numid == 0) {
+            LOGW(Ustica_Reset1, "%s: Invalid numid = %d!", __FUNCTION__, numid);
+            continue;
+        }
+
+        value = reg_cache_inorder[k].reg_default;
+        cache_idx = numid - codec_reg_num;
+        if (cache_idx < size)
+            reg_cache[cache_idx].reg_value = value;
+        Ustica_RegSet(numid, value);
+#ifdef DEBUG_USTICA
+        LOGI(Ustica_Reset2, "%s: resets ustica register 0x%lx to value --> 0x%lx",
+            __FUNCTION__,
+            reg_cache_inorder[k].reg_index,
+            value);
+#endif
+    }
+#ifdef ACM_ALSA_INIT
+	I2CDeInit(); //make sure to enable mixer before and close after this operation
+#endif
+}
+
+static void Ustica_GetTypeAndID(int *type, unsigned char *id){
+    LOGI(Ustica_GetTypeAndID, "%s: Get type and ID for ustica component", __FUNCTION__);
+    *type = COMPONENT_TYPE_POWER;
+#ifdef ACM_ALSA_INIT
+	I2CInit(); //make sure to enable mixer before and close after this operation
+#endif
+    Ustica_RegGet(USTICA_ID_REG, id);
+#ifdef ACM_ALSA_INIT
+	I2CDeInit(); //make sure to enable mixer before and close after this operation
+#endif
+}
+
+static ACH_ReturnCode Ustica_Handle(void *setting) {
+    ACH_ComponentParameter *param = (ACH_ComponentParameter *)setting;
+    unsigned char numid, value, cache_idx;
+
+    if (param && param->i2c.reg_value) {
+        numid = Ustica_GetRegNumId(param->i2c.reg_index);
+        if (numid > 0) {
+            //compare with register cache
+            cache_idx = numid - codec_reg_num;
+            value = (reg_cache[cache_idx].reg_value & ~param->i2c.reg_mask) | (*param->i2c.reg_value);
+            if ((reg_cache[cache_idx].reg_value & param->i2c.reg_mask) != (*param->i2c.reg_value)) {
+#ifdef DEBUG_USTICA
+                LOGI(Ustica_Handle, "%s: set register 0x%lx [0x%lx --> 0x%lx]",
+                    __FUNCTION__,
+                    param->i2c.reg_index,
+                    reg_cache[cache_idx].reg_value,
+                    value);
+#endif
+
+                reg_cache[cache_idx].reg_value = value;
+                Ustica_RegSet(numid, reg_cache[cache_idx].reg_value);
+            } else {
+#ifdef DEBUG_USTICA
+                LOGI(Ustica_Handle1, "%s: set register 0x%lx [0x%lx --> 0x%lx] (unchanged)",
+                    __FUNCTION__,
+                    param->i2c.reg_index,
+                    reg_cache[cache_idx].reg_value,
+                    reg_cache[cache_idx].reg_value);
+#endif
+            }
+        }
+    }
+
+    return ACH_RC_OK;
+}
diff --git a/marvell/services/audio/libacm/acm/src/acm_xml_parser.c b/marvell/services/audio/libacm/acm/src/acm_xml_parser.c
new file mode 100644
index 0000000..583362f
--- /dev/null
+++ b/marvell/services/audio/libacm/acm/src/acm_xml_parser.c
@@ -0,0 +1,1727 @@
+/*
+* 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_xml_parser"
+#define LOG_NDEBUG 0
+
+#include <string.h>
+#include <stdlib.h>
+#include <cutils/log.h>
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+#include "acm_xml_parser.h"
+
+#ifdef PXA1826_AUDIO
+#define UNUSEDPARAM(param) (void)param
+#else
+#define UNUSEDPARAM(param)
+#endif
+
+//--------------------------------------------------------------
+//-------- Internal Used Parsing Functions
+//--------------------------------------------------------------
+static unsigned short control_unit_id = INVALID_CTL_UNIT_ID + 1;
+static int gssp_record = 0;
+
+//utilities implemented in APH
+unsigned short _get_ctl_unit_id(const unsigned char *name, const APH_BasicElementsTable *basic_info);
+const unsigned char *_get_ctl_unit_name(unsigned short id, const APH_BasicElementsTable *basic_info);
+unsigned short _get_path_id(const unsigned char *path_identifier, APH_PathConfigurationTable *path_info);
+const unsigned char *_get_path_identifier(unsigned short path_id, APH_PathConfigurationTable *path_info);
+
+static int _parse_register_info(xmlNodePtr cur_node, APH_BasicElementsTable *table) {
+    unsigned char component_id = 0;
+    unsigned char reg_index = 0;;
+
+    //get component id index from parent tag
+    xmlChar *component = xmlGetProp(cur_node->parent, (const xmlChar *)"identifier");
+    component_id = COMPONENT_STR2ENUM(component);
+    xmlFree(component);
+
+    //parse <RegisterInfo> tag
+    if (!xmlHasProp(cur_node, (const xmlChar *)"index")) {
+        LOGE(_parse_register_info, "%s:L%d: missing mandatory attributes", __FUNCTION__, __LINE__);
+        return -1;
+    }
+    xmlChar *index = xmlGetProp(cur_node, (const xmlChar *)"index");
+    if (index) {
+        reg_index = (unsigned char)strtoul((const char *)(index), NULL, 16);
+        xmlFree(index);
+    }
+
+    cur_node = cur_node->xmlChildrenNode;
+    while (cur_node) {
+        //parse <Bits> tag
+        if (xmlStrcmp(cur_node->name, (const xmlChar *)"Bits") == 0) {
+            //allocate register info entry
+            APH_RegisterInfo *reg_info_entry = (APH_RegisterInfo *)malloc(sizeof(APH_RegisterInfo));
+            if (reg_info_entry == NULL) {
+                LOGE(_parse_register_info1, "%s/L%d: out of memory", __FUNCTION__, __LINE__);
+                return -1;
+            }
+            memset(reg_info_entry, 0, sizeof(APH_RegisterInfo));
+
+            reg_info_entry->component_id = component_id;
+            reg_info_entry->index = reg_index;
+
+            //field attribute
+            xmlChar *field = xmlGetProp(cur_node, (const xmlChar *)"field");
+            if (field) {
+                strcpy((char *)reg_info_entry->field, (const char *)(field));
+                xmlFree(field);
+            }
+
+            //range attribute
+            xmlChar *range = xmlGetProp(cur_node, (const xmlChar *)"range");
+            int start_bit = -1;
+            int stop_bit = -1;
+            char *start_bit_str, *stop_bit_str;
+            if (range) {
+                stop_bit_str = strtok((char *)range, ":");
+                if (stop_bit_str) {
+                    stop_bit = atoi(stop_bit_str);
+                    start_bit = stop_bit;
+                }
+                start_bit_str = strtok(NULL, ":");
+                if (start_bit_str) {
+                    start_bit = atoi(start_bit_str);
+                }
+                xmlFree(range);
+            }
+
+            reg_info_entry->field_shift = start_bit;
+            if (start_bit != -1 && start_bit == stop_bit) {
+                reg_info_entry->field_mask = (1 << start_bit);
+            } else if (start_bit < stop_bit) {
+                while (start_bit <= stop_bit) {
+                    reg_info_entry->field_mask |= (1 << start_bit);
+                    start_bit++;
+                }
+            }
+
+            //default attribute
+            xmlChar *default_value = xmlGetProp(cur_node, (const xmlChar *)"default");
+            if (default_value) {
+                reg_info_entry->field_default = (unsigned char)strtoul((const char *)(default_value), NULL, 2);
+                xmlFree(default_value);
+            }
+
+            //type attribute (optional)
+            if (xmlHasProp(cur_node, (const xmlChar *)"type")) {
+                xmlChar *type = xmlGetProp(cur_node, (const xmlChar *)"type");
+                if (xmlStrcmp(type, (const xmlChar *)"Gain") == 0) {
+                    reg_info_entry->field_type = REG_FIELD_TYPE_GAIN;
+                } else if (xmlStrcmp(type, (const xmlChar *)"Coeff") == 0) {
+                    reg_info_entry->field_type = REG_FIELD_TYPE_COEFF;
+                } else if (xmlStrcmp(type, (const xmlChar *)"Force") == 0) {
+                    reg_info_entry->field_type = REG_FIELD_TYPE_FORCE;
+                }
+
+                xmlFree(type);
+            }
+
+            //dispatch control unit id (for calibration)
+            reg_info_entry->control_unit_id = control_unit_id++;
+
+            //attach to reg info list
+            if (table->reg_info == NULL) {
+                table->reg_info = reg_info_entry;
+            } else {
+                APH_RegisterInfo *last_reg_info = table->reg_info;
+                while (last_reg_info->next) last_reg_info = last_reg_info->next;
+                last_reg_info->next = reg_info_entry;
+            }
+            table->reg_info_number++;
+#ifdef DEBUG_XML_PARSER
+            LOGD(_parse_register_info2, "%s: <RegisterInfo> component=%s index=0x%02x field=%s "
+                "mask=0x%02x shift=%d default=0x%02x type=%d control_unit_id=%d",
+                __FUNCTION__,
+                COMPONENT_ENUM2STR(reg_info_entry->component_id),
+                reg_info_entry->index,
+                reg_info_entry->field,
+                reg_info_entry->field_mask,
+                reg_info_entry->field_shift,
+                reg_info_entry->field_default,
+                reg_info_entry->field_type,
+                reg_info_entry->control_unit_id);
+#endif
+        }
+
+        cur_node = cur_node->next;
+    }
+
+    return 0;
+}
+
+static int _parse_hci_info(xmlNodePtr cur_node, APH_BasicElementsTable *table) {
+    //allocate hci info entry
+    APH_HCIInfo *hci_info_entry = (APH_HCIInfo *)malloc(sizeof(APH_HCIInfo));
+    if (hci_info_entry == NULL) {
+        LOGE(_parse_hci_info, "%s/L%d: out of memory", __FUNCTION__, __LINE__);
+        return -1;
+    }
+    memset(hci_info_entry, 0, sizeof(APH_HCIInfo));
+
+    //get component id from parent tag
+    xmlChar *component = xmlGetProp(cur_node->parent, (const xmlChar *)"identifier");
+    if (component) {
+        hci_info_entry->component_id = COMPONENT_STR2ENUM(component);
+        xmlFree(component);
+    }
+
+    //parse <HCIInfo> tag
+    xmlChar *name = xmlGetProp(cur_node, (const xmlChar *)"name");
+    if (name) {
+        strcpy((char *)hci_info_entry->name, (const char *)(name));
+        xmlFree(name);
+    }
+
+    xmlChar *ocf = xmlGetProp(cur_node, (const xmlChar *)"ocf");
+    if (ocf) {
+        hci_info_entry->ocf = (unsigned char)strtoul((const char *)(ocf), NULL, 16);
+        xmlFree(ocf);
+    }
+
+    xmlChar *ogf = xmlGetProp(cur_node, (const xmlChar *)"ogf");
+    if (ogf) {
+        hci_info_entry->ogf = (unsigned char)strtoul((const char *)(ogf), NULL, 16);
+        xmlFree(ogf);
+    }
+
+    xmlChar *length = xmlGetProp(cur_node, (const xmlChar *)"length");
+    if (length) {
+        hci_info_entry->length = (unsigned short)atoi((const char *)length);
+        xmlFree(length);
+    }
+
+    //dispatch control unit id (for calibration)
+    hci_info_entry->control_unit_id = control_unit_id++;
+
+    //attach to hci info list
+    if (table->hci_info == NULL) {
+        table->hci_info = hci_info_entry;
+    } else {
+        APH_HCIInfo *last_hci_info = table->hci_info;
+        while (last_hci_info->next) last_hci_info = last_hci_info->next;
+        last_hci_info->next = hci_info_entry;
+    }
+    table->hci_info_number++;
+#ifdef DEBUG_XML_PARSER
+    LOGD(_parse_hci_info1, "%s: <HCIInfo> component=%s name=%s ocf=0x%02x "
+        "ogf=0x%02x length=%d control_unit_id=%d",
+        __FUNCTION__,
+        COMPONENT_ENUM2STR(hci_info_entry->component_id),
+        hci_info_entry->name,
+        hci_info_entry->ocf,
+        hci_info_entry->ogf,
+        hci_info_entry->length,
+        hci_info_entry->control_unit_id);
+#endif
+
+    return 0;
+}
+
+static int _parse_gpio_info(xmlNodePtr cur_node, APH_BasicElementsTable *table) {
+    unsigned char component_id;
+
+    //get component id from parent tag
+    xmlChar *component = xmlGetProp(cur_node->parent, (const xmlChar *)"identifier");
+    component_id = COMPONENT_STR2ENUM(component);
+    xmlFree(component);
+
+    xmlNodePtr child_node = cur_node->xmlChildrenNode;
+    while (child_node) {
+        //parse <GPIO> tag
+        if (xmlStrcmp(child_node->name, (const xmlChar *)"GPIO") == 0) {
+            //allocate gpio info entry
+            APH_GPIOInfo *gpio_info_entry = (APH_GPIOInfo *)malloc(sizeof(APH_GPIOInfo));
+            if (gpio_info_entry == NULL) {
+                LOGE(_parse_gpio_info, "%s/L%d: out of memory", __FUNCTION__, __LINE__);
+                return -1;
+            }
+            memset(gpio_info_entry, 0, sizeof(APH_GPIOInfo));
+
+            gpio_info_entry->component_id = component_id;
+
+            xmlChar *name = xmlGetProp(child_node, (const xmlChar *)"name");
+            if (name) {
+                strcpy((char *)gpio_info_entry->name, (const char *)name);
+                xmlFree(name);
+            }
+
+            xmlChar *port = xmlGetProp(child_node, (const xmlChar *)"port");
+            if (port) {
+                gpio_info_entry->port = (unsigned char)atoi((const char *)port);
+                xmlFree(port);
+            }
+
+            //dispatch control unit id (for calibration)
+            gpio_info_entry->control_unit_id = control_unit_id++;
+
+            //attach to gpio info list
+            if (table->gpio_info == NULL) {
+                table->gpio_info = gpio_info_entry;
+            } else {
+                APH_GPIOInfo *last_gpio_info = table->gpio_info;
+                while (last_gpio_info->next) last_gpio_info = last_gpio_info->next;
+                last_gpio_info->next = gpio_info_entry;
+            }
+            table->gpio_info_number++;
+#ifdef DEBUG_XML_PARSER
+            LOGD(_parse_gpio_info1, "%s: <GPIOInfo> component=%s port=%d control_unit_id=%d",
+                __FUNCTION__,
+                COMPONENT_ENUM2STR(gpio_info_entry->component_id),
+                gpio_info_entry->port,
+                gpio_info_entry->control_unit_id);
+#endif
+        }
+
+        child_node = child_node->next;
+    }
+
+    return 0;
+}
+
+static int _map_path_identifier(xmlNodePtr cur_node, APH_PathConfigurationTable *table) {
+    unsigned short path_id = INVALID_PATH_ID + 1;
+
+    while (cur_node) {
+        //search <AudioPath> tag
+        if (xmlStrcmp(cur_node->name, (const xmlChar *)"AudioPath")) {
+            cur_node = cur_node->next;
+            continue;
+        }
+
+        xmlChar *path_identifier = xmlGetProp(cur_node, (const xmlChar *)"identifier");
+        if (path_identifier) {
+            if (table->path_id_mapping == NULL) {
+                table->path_id_mapping = (APH_PathIdMapping *)malloc(sizeof(APH_PathIdMapping));
+                if (table->path_id_mapping == NULL) {
+                    LOGE(_map_path_identifier, "%s/L%d: out of memory", __FUNCTION__, __LINE__);
+                    xmlFree(path_identifier);
+                    return -1;
+                }
+                memset(table->path_id_mapping, 0, sizeof(APH_PathIdMapping));
+                table->path_id_mapping->path_id = path_id++;
+                strcpy((char *)table->path_id_mapping->path_identifier, (const char *)path_identifier);
+                table->path_number++;
+#ifdef DEBUG_XML_PARSER
+                LOGD(_map_path_identifier1, "%s: path_identifier=%s, path_id=%d",
+                    __FUNCTION__,
+                    table->path_id_mapping->path_identifier,
+                    table->path_id_mapping->path_id);
+#endif
+            } else {
+                //search existing path
+                APH_PathIdMapping *path_id_mapping = table->path_id_mapping;
+                APH_PathIdMapping *prev_path_id_mapping = path_id_mapping;
+                int path_existed = 0;
+                while (path_id_mapping) {
+                    if (strcmp((char *)path_id_mapping->path_identifier, (const char *)path_identifier) == 0) {
+                        path_existed = 1;
+                        break;
+                    }
+
+                    prev_path_id_mapping = path_id_mapping;
+                    path_id_mapping = path_id_mapping->next;
+                }
+
+                if (!path_existed) {
+                    prev_path_id_mapping->next = (APH_PathIdMapping *)malloc(sizeof(APH_PathIdMapping));
+                    if (prev_path_id_mapping->next == NULL) {
+                        LOGE(_map_path_identifier2, "%s/L%d: out of memory", __FUNCTION__, __LINE__);
+                        xmlFree(path_identifier);
+                        return -1;
+                    }
+                    memset(prev_path_id_mapping->next, 0, sizeof(APH_PathIdMapping));
+                    prev_path_id_mapping->next->path_id = path_id++;
+                    strcpy((char *)prev_path_id_mapping->next->path_identifier, (const char *)path_identifier);
+                    table->path_number++;
+#ifdef DEBUG_XML_PARSER
+                    LOGD(_map_path_identifier3, "%s: path_identifier=%s, path_id=%d",
+                        __FUNCTION__,
+                        prev_path_id_mapping->next->path_identifier,
+                        prev_path_id_mapping->next->path_id);
+#endif
+                }
+            }
+            xmlFree(path_identifier);
+        }
+
+        cur_node = cur_node->next;
+    }
+
+    return 0;
+}
+
+static APH_ControlUnitConfiguration *_parse_register(xmlNodePtr cur_node, APH_BasicElementsTable *basic_info) {
+    APH_ControlUnitConfiguration *ctl_unit_entry =
+        (APH_ControlUnitConfiguration *)malloc(sizeof(APH_ControlUnitConfiguration));
+    if (ctl_unit_entry == NULL) {
+        LOGE(_parse_register, "%s/L%d: out of memory", __FUNCTION__, __LINE__);
+        return NULL;
+    }
+    memset(ctl_unit_entry, 0, sizeof(APH_ControlUnitConfiguration));
+
+    //parse <Register> tag
+    xmlChar *field = xmlGetProp(cur_node, (const xmlChar *)"field");
+    if (field) {
+        ctl_unit_entry->control_unit_id = _get_ctl_unit_id(field, basic_info);
+        APH_RegisterInfo *reg_info = basic_info->reg_info;
+        while (reg_info) {
+            if (strcmp((char *)reg_info->field, (const char *)field) == 0) {
+                ctl_unit_entry->i2c_unit.reg_index = reg_info->index;
+                ctl_unit_entry->i2c_unit.reg_mask = reg_info->field_mask;
+                ctl_unit_entry->i2c_unit.reg_shift = reg_info->field_shift;
+                ctl_unit_entry->i2c_unit.reg_type = reg_info->field_type;
+#ifdef DEBUG_XML_PARSER
+                LOGD(_parse_register1, "%s: <Register> field=%s reg_index=0x%02x, reg_mask=0x%02x, reg_shift=0x%02x, reg_type=%d",
+                    __FUNCTION__,
+                    field,
+                    ctl_unit_entry->i2c_unit.reg_index,
+                    ctl_unit_entry->i2c_unit.reg_mask,
+                    ctl_unit_entry->i2c_unit.reg_shift,
+                    ctl_unit_entry->i2c_unit.reg_type);
+#endif
+                break;
+            }
+
+            reg_info = reg_info->next;
+        }
+        xmlFree(field);
+    }
+
+    if (xmlHasProp(cur_node, (const xmlChar *)"value")) {
+        xmlChar *value = xmlGetProp(cur_node, (const xmlChar *)"value");
+        if (value) {
+            //Notes: treat register as normal type if value is specified
+            if (ctl_unit_entry->i2c_unit.reg_type != REG_FIELD_TYPE_FORCE) {
+                ctl_unit_entry->i2c_unit.reg_type |= REG_FIELD_TYPE_NORMAL;
+            }
+            ctl_unit_entry->i2c_unit.length = 1;
+            ctl_unit_entry->i2c_unit.reg_value = (unsigned char *)malloc(sizeof(unsigned char));
+            if (ctl_unit_entry->i2c_unit.reg_value == NULL) {
+                LOGE(_parse_register2, "%s/L%d: out of memory", __FUNCTION__, __LINE__);
+                free(ctl_unit_entry);
+                xmlFree(value);
+                return NULL;
+            }
+
+            *ctl_unit_entry->i2c_unit.reg_value = (unsigned char)strtoul((const char *)value, NULL, 2);
+            xmlFree(value);
+#ifdef DEBUG_XML_PARSER
+            LOGD(_parse_register3, "%s: <Register> value=0x%02x", __FUNCTION__, *ctl_unit_entry->i2c_unit.reg_value);
+#endif
+        }
+    }
+
+    if (xmlHasProp(cur_node, (const xmlChar *)"misc")) {
+        xmlChar *misc = xmlGetProp(cur_node, (const xmlChar*)"misc");
+        if (misc) {
+            if (strcmp((const char *)misc, "mic1") == 0) {
+                ctl_unit_entry->i2c_unit.reg_misc = REG_MISC_MIC1;
+            } else if (strcmp((const char *)misc, "mic2") == 0) {
+                ctl_unit_entry->i2c_unit.reg_misc = REG_MISC_MIC2;
+            } else if (strcmp((const char *)misc, "dualmic") == 0) {
+                ctl_unit_entry->i2c_unit.reg_misc = REG_MISC_DUAL_MIC;
+            } else if (strcmp((const char *)misc, "slave") == 0) {
+                ctl_unit_entry->i2c_unit.reg_misc = REG_MISC_SLAVE;
+            } else if (strcmp((const char *)misc, "master") == 0) {
+                ctl_unit_entry->i2c_unit.reg_misc = REG_MISC_MASTER;
+            } else if (strcmp((const char *)misc, "nbrate") == 0) {
+                ctl_unit_entry->i2c_unit.reg_misc = REG_MISC_NB_RATE;
+            } else if (strcmp((const char *)misc, "wbrate") == 0) {
+                ctl_unit_entry->i2c_unit.reg_misc = REG_MISC_WB_RATE;
+            } else if (strcmp((const char *)misc, "voip") == 0) {
+                ctl_unit_entry->i2c_unit.reg_misc = REG_MISC_VOIP_RATE;
+            } else if (strcmp((const char *)misc, "default") == 0) {
+                ctl_unit_entry->i2c_unit.reg_misc = REG_MISC_DEFAULT_RATE;
+            } else {
+                ctl_unit_entry->i2c_unit.reg_misc = REG_MISC_NONE;
+                LOGE(_parse_register4, "%s: unknown register misc!!!!", __FUNCTION__);
+            }
+            xmlFree(misc);
+        }
+    } else {
+        ctl_unit_entry->i2c_unit.reg_misc = REG_MISC_NONE;
+    }
+
+    return ctl_unit_entry;
+}
+
+static APH_ControlUnitConfiguration *_parse_hci(xmlNodePtr cur_node, APH_BasicElementsTable *basic_info) {
+    APH_ControlUnitConfiguration *ctl_unit_entry =
+        (APH_ControlUnitConfiguration *)malloc(sizeof(APH_ControlUnitConfiguration));
+    if (ctl_unit_entry == NULL) {
+        LOGE(_parse_hci, "%s/L%d: out of memory", __FUNCTION__, __LINE__);
+        return NULL;
+    }
+    memset(ctl_unit_entry, 0, sizeof(APH_ControlUnitConfiguration));
+
+    //parse <HCI> tag
+    xmlChar *name = xmlGetProp(cur_node, (const xmlChar *)"name");
+    if (name) {
+        ctl_unit_entry->control_unit_id = _get_ctl_unit_id(name, basic_info);
+        APH_HCIInfo *hci_info = basic_info->hci_info;
+        while (hci_info) {
+            if (strcmp((char *)hci_info->name, (const char *)name) == 0) {
+                ctl_unit_entry->hci_unit.hci_ocf = hci_info->ocf;
+                ctl_unit_entry->hci_unit.hci_ogf = hci_info->ogf;
+                ctl_unit_entry->hci_unit.length  = hci_info->length;
+                ctl_unit_entry->hci_unit.hci_parameters = (unsigned char *)malloc(hci_info->length * sizeof(unsigned char));
+                if (ctl_unit_entry->hci_unit.hci_parameters == NULL) {
+                    LOGE(_parse_hci1, "%s/L%d: out of memory", __FUNCTION__, __LINE__);
+                    free(ctl_unit_entry);
+                    xmlFree(name);
+                    return NULL;
+                }
+                memset(ctl_unit_entry->hci_unit.hci_parameters, 0, hci_info->length * sizeof(unsigned char));
+#ifdef DEBUG_XML_PARSER
+                LOGD(_parse_hci2, "%s: <HCI> name=%s hci_ocf=0x%02x, hci_ogf=0x%02x, length=%d",
+                    __FUNCTION__,
+                    name,
+                    ctl_unit_entry->hci_unit.hci_ocf,
+                    ctl_unit_entry->hci_unit.hci_ogf,
+                    ctl_unit_entry->hci_unit.length);
+#endif
+                break;
+            }
+
+            hci_info = hci_info->next;
+        }
+        xmlFree(name);
+    }
+
+    xmlNodePtr child_node = cur_node->xmlChildrenNode;
+    int param_count = 0;
+    while (child_node) {
+        //parse <Param> tag
+        if (xmlStrcmp(child_node->name, (const xmlChar *)"Param") == 0) {
+            if (param_count >= ctl_unit_entry->hci_unit.length) {
+                LOGW(_parse_hci3, "%s: exceed HCI parameter number %d", __FUNCTION__, ctl_unit_entry->hci_unit.length);
+                break;
+            }
+
+            xmlChar *param = xmlNodeListGetString(child_node->doc, child_node->xmlChildrenNode, 1);
+            if (param) {
+                if (ctl_unit_entry->hci_unit.hci_parameters) {
+                    ctl_unit_entry->hci_unit.hci_parameters[param_count]
+                        = (unsigned char)strtoul((const char *)param, NULL, 16);
+#ifdef DEBUG_XML_PARSER
+                    LOGD(_parse_hci4, "%s: <Param> param=0x%02x",
+                        __FUNCTION__,
+                        ctl_unit_entry->hci_unit.hci_parameters[param_count]);
+#endif
+                   param_count++;
+                }
+                xmlFree(param);
+            }
+        }
+
+        child_node = child_node->next;
+    }
+
+    return ctl_unit_entry;
+}
+
+static APH_ControlUnitConfiguration *_parse_gpio(xmlNodePtr cur_node, APH_BasicElementsTable *basic_info) {
+    APH_ControlUnitConfiguration *ctl_unit_entry =
+        (APH_ControlUnitConfiguration *)malloc(sizeof(APH_ControlUnitConfiguration));
+    if (ctl_unit_entry == NULL) {
+        LOGE(_parse_gpio, "%s/L%d: out of memory", __FUNCTION__, __LINE__);
+        return NULL;
+    }
+    memset(ctl_unit_entry, 0, sizeof(APH_ControlUnitConfiguration));
+
+    //parse <GPIO> tag
+    xmlChar *name = xmlGetProp(cur_node, (const xmlChar *)"name");
+    if (name) {
+        ctl_unit_entry->control_unit_id = _get_ctl_unit_id(name, basic_info);
+        APH_GPIOInfo *gpio_info = basic_info->gpio_info;
+        while (gpio_info) {
+            if (strcmp((const char *)name, (const char *)gpio_info->name) == 0) {
+                ctl_unit_entry->gpio_unit.gpio_port = gpio_info->port;
+                break;
+            }
+
+            gpio_info = gpio_info->next;
+        }
+        xmlFree(name);
+    }
+
+    xmlChar *value = xmlGetProp(cur_node, (const xmlChar *)"value");
+    if (value) {
+        ctl_unit_entry->gpio_unit.gpio_value = (unsigned char)atoi((const char *)value);
+        xmlFree(value);
+    }
+
+#ifdef DEBUG_XML_PARSER
+            LOGD(_parse_gpio1, "%s: <GPIO> port=%d, value=%d",
+                __FUNCTION__,
+                ctl_unit_entry->gpio_unit.gpio_port,
+                ctl_unit_entry->gpio_unit.gpio_value);
+#endif
+
+    return ctl_unit_entry;
+}
+
+static APH_ControlUnitConfiguration *_parse_delay(xmlNodePtr cur_node, APH_BasicElementsTable *basic_info) {
+    UNUSEDPARAM(basic_info);
+
+    APH_ControlUnitConfiguration *ctl_unit_entry =
+        (APH_ControlUnitConfiguration *)malloc(sizeof(APH_ControlUnitConfiguration));
+    if (ctl_unit_entry == NULL) {
+        LOGE(_parse_delay, "%s/L%d: out of memory", __FUNCTION__, __LINE__);
+        return NULL;
+    }
+    memset(ctl_unit_entry, 0, sizeof(APH_ControlUnitConfiguration));
+
+    //parse <Delay> tag
+    ctl_unit_entry->control_unit_id = INVALID_CTL_UNIT_ID;
+    xmlChar *value = xmlGetProp(cur_node, (const xmlChar *)"value");
+    if (value) {
+        ctl_unit_entry->delay_unit.delay_value = (unsigned int)atoi((const char *)value);
+        xmlFree(value);
+    }
+
+#ifdef DEBUG_XML_PARSER
+            LOGD(_parse_delay1, "%s: <Delay> value=%d",
+                __FUNCTION__,
+                ctl_unit_entry->delay_unit.delay_value);
+#endif
+    if (xmlHasProp(cur_node, (const xmlChar *)"misc")) {
+        xmlChar *misc = xmlGetProp(cur_node, (const xmlChar*)"misc");
+        if (misc) {
+            if (strcmp((const char *)misc, "mic1") == 0) {
+                ctl_unit_entry->delay_unit.delay_misc = REG_MISC_MIC1;
+            } else if (strcmp((const char *)misc, "mic2") == 0) {
+                ctl_unit_entry->delay_unit.delay_misc = REG_MISC_MIC2;
+            } else if (strcmp((const char *)misc, "dualmic") == 0) {
+                ctl_unit_entry->delay_unit.delay_misc = REG_MISC_DUAL_MIC;
+            } else if (strcmp((const char *)misc, "slave") == 0) {
+                ctl_unit_entry->delay_unit.delay_misc = REG_MISC_SLAVE;
+            } else if (strcmp((const char *)misc, "master") == 0) {
+                ctl_unit_entry->delay_unit.delay_misc = REG_MISC_MASTER;
+            } else if (strcmp((const char *)misc, "nbrate") == 0) {
+                ctl_unit_entry->delay_unit.delay_misc = REG_MISC_NB_RATE;
+            } else if (strcmp((const char *)misc, "wbrate") == 0) {
+                ctl_unit_entry->delay_unit.delay_misc = REG_MISC_WB_RATE;
+            } else if (strcmp((const char *)misc, "voip") == 0) {
+                ctl_unit_entry->delay_unit.delay_misc = REG_MISC_VOIP_RATE;
+            } else if (strcmp((const char *)misc, "default") == 0) {
+                ctl_unit_entry->delay_unit.delay_misc = REG_MISC_DEFAULT_RATE;
+            } else if (strcmp((const char *)misc, "force") == 0) {
+                ctl_unit_entry->delay_unit.delay_misc = REG_MISC_FORCE_DELAY;
+            } else {
+                ctl_unit_entry->delay_unit.delay_misc = REG_MISC_NONE;
+                LOGE(_parse_delay2, "%s: unknown register misc!!!!", __FUNCTION__);
+            }
+            xmlFree(misc);
+        }
+    } else {
+        ctl_unit_entry->delay_unit.delay_misc = REG_MISC_NONE;
+    }
+
+    return ctl_unit_entry;
+}
+
+static APH_ComponentConfiguration *_parse_audio_component(xmlNodePtr cur_node, APH_BasicElementsTable *basic_info) {
+    //allocate component configuration entry
+    APH_ComponentConfiguration *component_config_entry
+        = (APH_ComponentConfiguration *)malloc(sizeof(APH_ComponentConfiguration));
+    if (component_config_entry == NULL) {
+        LOGE(_parse_audio_component, "%s/L%d: out of memory", __FUNCTION__, __LINE__);
+        return NULL;
+    }
+    memset(component_config_entry, 0, sizeof(APH_ComponentConfiguration));
+
+    //parse <AudioComponent> tag
+    xmlChar *component_identifier = xmlGetProp(cur_node, (const xmlChar *)"identifier");
+    component_config_entry->component_id = COMPONENT_STR2ENUM(component_identifier);
+    xmlFree(component_identifier);
+    xmlChar *control_protocol = xmlGetProp(cur_node, (const xmlChar *)"control_protocol");
+    component_config_entry->component_ctl_protocol = PROTOCOL_STR2ENUM(control_protocol);
+    xmlFree(control_protocol);
+
+#ifdef DEBUG_XML_PARSER
+    LOGD(_parse_audio_component1, "%s: <AudioComponent> component_identifier=%s control_protocol=%s, ctl_unit_number=%ld",
+        __FUNCTION__,
+        COMPONENT_ENUM2STR(component_config_entry->component_id),
+        PROTOCOL_ENUM2STR(component_config_entry->component_ctl_protocol),
+        xmlChildElementCount(cur_node));
+#endif
+
+    xmlNodePtr child_node = cur_node->xmlChildrenNode;
+    while (child_node) {
+        if (xmlStrcmp(child_node->name, (const xmlChar *)"Register") == 0) {
+            //parse <Register> tag
+            APH_ControlUnitConfiguration *ctl_unit_entry = _parse_register(child_node, basic_info);
+            if (component_config_entry->component_ctl_unit_array == NULL) {
+                component_config_entry->component_ctl_unit_array = ctl_unit_entry;
+            } else {
+                APH_ControlUnitConfiguration *last_ctl_unit_entry = component_config_entry->component_ctl_unit_array;
+                while (last_ctl_unit_entry->next) last_ctl_unit_entry = last_ctl_unit_entry->next;
+                last_ctl_unit_entry->next = ctl_unit_entry;
+            }
+            component_config_entry->component_ctl_unit_num++;
+        } else if (xmlStrcmp(child_node->name, (const xmlChar *)"HCI") == 0) {
+            //parse <HCI> tag
+            APH_ControlUnitConfiguration *ctl_unit_entry = _parse_hci(child_node, basic_info);
+            if (component_config_entry->component_ctl_unit_array == NULL) {
+                component_config_entry->component_ctl_unit_array = ctl_unit_entry;
+            } else {
+                APH_ControlUnitConfiguration *last_ctl_unit_entry = component_config_entry->component_ctl_unit_array;
+                while (last_ctl_unit_entry->next) last_ctl_unit_entry = last_ctl_unit_entry->next;
+                last_ctl_unit_entry->next = ctl_unit_entry;
+            }
+            component_config_entry->component_ctl_unit_num++;
+        } else if (xmlStrcmp(child_node->name, (const xmlChar *)"GPIO") == 0) {
+            //parse <GPIO> tag
+            APH_ControlUnitConfiguration *ctl_unit_entry = _parse_gpio(child_node, basic_info);
+            if (component_config_entry->component_ctl_unit_array == NULL) {
+                component_config_entry->component_ctl_unit_array = ctl_unit_entry;
+            } else {
+                APH_ControlUnitConfiguration *last_ctl_unit_entry = component_config_entry->component_ctl_unit_array;
+                while (last_ctl_unit_entry->next) last_ctl_unit_entry = last_ctl_unit_entry->next;
+                last_ctl_unit_entry->next = ctl_unit_entry;
+            }
+            component_config_entry->component_ctl_unit_num++;
+        } else if (xmlStrcmp(child_node->name, (const xmlChar *)"Delay") == 0) {
+            //parse <Delay> tag
+            APH_ControlUnitConfiguration *ctl_unit_entry = _parse_delay(child_node, basic_info);
+            if (component_config_entry->component_ctl_unit_array == NULL) {
+                component_config_entry->component_ctl_unit_array = ctl_unit_entry;
+            } else {
+                APH_ControlUnitConfiguration *last_ctl_unit_entry = component_config_entry->component_ctl_unit_array;
+                while (last_ctl_unit_entry->next) last_ctl_unit_entry = last_ctl_unit_entry->next;
+                last_ctl_unit_entry->next = ctl_unit_entry;
+            }
+            component_config_entry->component_ctl_unit_num++;
+        }
+
+        child_node = child_node->next;
+    }
+
+    return component_config_entry;
+}
+
+static int _parse_operation(xmlNodePtr cur_node, APH_PathConfigurationTable *table, APH_BasicElementsTable *basic_info, xmlChar *path_identifier) {
+    //allocate path configuration entry
+    APH_PathConfiguration *path_config_entry = (APH_PathConfiguration *)malloc(sizeof(APH_PathConfiguration));
+    if (path_config_entry == NULL) {
+        LOGE(_parse_operation, "%s/L%d: out of memory", __FUNCTION__, __LINE__);
+        return -1;
+    }
+    memset(path_config_entry, 0, sizeof(APH_PathConfiguration));
+
+    //get path identifier from parent tag
+    path_config_entry->path_id = _get_path_id(path_identifier, table);
+
+    //parse <Operation> tag
+    xmlChar *path_op = xmlGetProp(cur_node, (const xmlChar *)"identifier");
+    path_config_entry->path_op_id = OPERATION_STR2ENUM(path_op);
+    xmlFree(path_op);
+
+    if (xmlHasProp(cur_node, (const xmlChar *)"ref_path_identifier")) {
+        xmlChar *path_ref_identifier = xmlGetProp(cur_node, (const xmlChar *)"ref_path_identifier");
+        path_config_entry->path_ref_id = _get_path_id(path_ref_identifier, table);
+        xmlFree(path_ref_identifier);
+    }
+
+#ifdef DEBUG_XML_PARSER
+    LOGD(_parse_operation1, "%s: <AudioPath> path_identifier=%s path_operation=%s path_ref_identifier=%s, path_component_number=%ld",
+        __FUNCTION__,
+        _get_path_identifier(path_config_entry->path_id, table),
+        OPERATION_ENUM2STR(path_config_entry->path_op_id),
+        _get_path_identifier(path_config_entry->path_ref_id, table),
+        xmlChildElementCount(cur_node));
+#endif
+
+    xmlNodePtr child_node = cur_node->xmlChildrenNode;
+    while (child_node) {
+        //parse <AudioComponent> tag
+        if (xmlStrcmp(child_node->name, (const xmlChar *)"AudioComponent") == 0) {
+            // check whether the component is needed to ignore parsing
+            int ignore = 0;
+            if (xmlHasProp(child_node, (const xmlChar *)"misc")) {
+                xmlChar *misc = xmlGetProp(child_node, (const xmlChar*)"misc");
+                if (strcmp((const char *)misc, "SSP") == 0) {
+                    if (gssp_record == 1) {
+                        // ignore registers for SSP under GSSP record mode
+                        ignore = 1;
+                    }
+                } else if (strcmp((const char *)misc, "GSSP") == 0) {
+                    if (gssp_record == 0) {
+                        // ignore registers for GSSP under SSP record mode
+                        ignore = 1;
+                    }
+                }
+#ifndef WITH_GPIO_SPKR_SWITCH
+                else if (strcmp((const char *)misc, "GPIO_SPKR_SWITCH") == 0) {
+                    // ignore gpios for non-gpio dual speaker mode.
+                    ignore = 1;
+                }
+#endif
+                else {
+                    LOGE(_parse_operation2, "%s: unknown AudioComponent misc!!!!", __FUNCTION__);
+                }
+                xmlFree(misc);
+            }
+
+            if (ignore == 0) {
+            //add one path component
+            APH_ComponentConfiguration *path_component_entry = _parse_audio_component(child_node, basic_info);
+            if (path_config_entry->path_component_array == NULL) {
+                path_config_entry->path_component_array = path_component_entry;
+            } else {
+                APH_ComponentConfiguration *last_path_component_entry = path_config_entry->path_component_array;
+                while (last_path_component_entry->next) last_path_component_entry = last_path_component_entry->next;
+                last_path_component_entry->next = path_component_entry;
+            }
+            path_config_entry->path_component_num++;
+            }
+        }
+
+        child_node = child_node->next;
+    }
+
+    //add one path configuration entry into path configuration table
+    if (table->path_configuration == NULL) {
+        table->path_configuration = path_config_entry;
+    } else {
+        APH_PathConfiguration *last_path_configuration = table->path_configuration;
+        while (last_path_configuration->next) last_path_configuration = last_path_configuration->next;
+        last_path_configuration->next = path_config_entry;
+    }
+
+    return 0;
+}
+
+static int _parse_gain(xmlNodePtr cur_node,
+    APH_GainConfigurationTable *table,
+    APH_BasicElementsTable *basic_info,
+    APH_PathConfigurationTable *path_info,
+    xmlChar *path_identifier, xmlChar *component) {
+    //allocate gain configuration entry
+    APH_GainConfiguration *gain_config_entry = (APH_GainConfiguration *)malloc(sizeof(APH_GainConfiguration));
+    if (gain_config_entry == NULL) {
+        LOGE(_parse_gain, "%s/L%d: out of memory", __FUNCTION__, __LINE__);
+        return -1;
+    }
+    memset(gain_config_entry, 0, sizeof(APH_GainConfiguration));
+
+    //get path id from parent tag
+    gain_config_entry->path_id = _get_path_id(path_identifier, path_info);
+
+    //get component id from parent tag
+    gain_config_entry->component_id = COMPONENT_STR2ENUM(component);
+
+    //parse <Gain> tag
+    xmlChar *gain_name = xmlGetProp(cur_node, (const xmlChar *)"name");
+    gain_config_entry->gain_id = _get_ctl_unit_id(gain_name, basic_info);
+    xmlFree(gain_name);
+
+#ifdef DEBUG_XML_PARSER
+    LOGD(_parse_gain1, "%s: <Gain> path_identifier=%s component_identifier=%s gain_name=%s mapping_number=%ld",
+        __FUNCTION__,
+        _get_path_identifier(gain_config_entry->path_id, path_info),
+        COMPONENT_ENUM2STR(gain_config_entry->component_id),
+        _get_ctl_unit_name(gain_config_entry->gain_id, basic_info),
+        xmlChildElementCount(cur_node));
+#endif
+
+    xmlNodePtr child_node = cur_node->xmlChildrenNode;
+    while (child_node) {
+        //parse <Value> tag
+        if (xmlStrcmp(child_node->name, (const xmlChar *)"Value") == 0) {
+            //allocate volume gain mapping entry
+            APH_VolumeGainMapping *volume_gain_entry = (APH_VolumeGainMapping *)malloc(sizeof(APH_VolumeGainMapping));
+            if (volume_gain_entry == NULL) {
+                LOGE(_parse_gain2, "%s/L%d: out of memory", __FUNCTION__, __LINE__);
+                free(gain_config_entry);
+                return -1;
+            }
+            memset(volume_gain_entry, 0, sizeof(APH_VolumeGainMapping));
+
+            xmlChar *volume = xmlGetProp(child_node, (const xmlChar *)"volume");
+            if (volume) {
+                volume_gain_entry->volume = (unsigned char)atoi((const char *)volume);
+                xmlFree(volume);
+            }
+            xmlChar *value = xmlNodeListGetString(child_node->doc, child_node->xmlChildrenNode, 1);
+            if (value) {
+                volume_gain_entry->value = (unsigned char)strtoul((const char *)value, NULL, 16);
+                xmlFree(value);
+            }
+
+            //attach to volume gain mapping list
+            if (gain_config_entry->volume_gain_mapping == NULL) {
+                gain_config_entry->volume_gain_mapping = volume_gain_entry;
+            } else {
+                APH_VolumeGainMapping *last_volume_gain = gain_config_entry->volume_gain_mapping;
+                while (last_volume_gain->next) last_volume_gain = last_volume_gain->next;
+                last_volume_gain->next = volume_gain_entry;
+            }
+            gain_config_entry->mapping_number++;
+#ifdef DEBUG_XML_PARSER
+            LOGD(_parse_gain3, "%s: <Value> volume=%d value=0x%02x",
+                __FUNCTION__,
+                volume_gain_entry->volume,
+                volume_gain_entry->value);
+#endif
+        }
+
+        child_node = child_node->next;
+    }
+
+    //add one gain configuration into gain configuration table
+    if (table->gain_configuration == NULL) {
+        table->gain_configuration = gain_config_entry;
+    } else {
+        APH_GainConfiguration *last_gain_config = table->gain_configuration;
+        while (last_gain_config->next) last_gain_config = last_gain_config->next;
+        last_gain_config->next = gain_config_entry;
+    }
+    table->gain_number++;
+
+    return 0;
+}
+
+static int _parse_coeff(xmlNodePtr cur_node,
+    APH_CoeffConfiguration *coeff_config_entry,
+    APH_BasicElementsTable *basic_info,
+    APH_PathConfigurationTable *path_info) {
+    UNUSEDPARAM(path_info);
+
+    //allocate coeff configuration group
+    APH_Coefficient_Group *coeff_configgroup_entry = (APH_Coefficient_Group *)malloc(sizeof(APH_Coefficient_Group));
+    if (coeff_configgroup_entry == NULL) {
+        LOGE(_parse_coeff, "%s/L%d: out of memory", __FUNCTION__, __LINE__);
+        return -1;
+    }
+    memset(coeff_configgroup_entry, 0, sizeof(APH_Coefficient_Group));
+
+    //parse <Coeff> tag
+    xmlChar *coeff_name = xmlGetProp(cur_node, (const xmlChar *)"name");
+    coeff_configgroup_entry->coeff_id = _get_ctl_unit_id(coeff_name, basic_info);
+    xmlFree(coeff_name);
+
+#ifdef DEBUG_XML_PARSER
+    LOGD(_parse_coeff1, "%s: <Coeff> path_identifier=%s component_identifier=%s operation_identifier=%s coeff_name=%s coeff_number=%ld",
+        __FUNCTION__,
+        _get_path_identifier(coeff_config_entry->path_id, path_info),
+        COMPONENT_ENUM2STR(coeff_config_entry->component_id),
+        OPERATION_ENUM2STR(coeff_config_entry->path_op_id),
+        _get_ctl_unit_name(coeff_configgroup_entry->coeff_id, basic_info),
+        xmlChildElementCount(cur_node));
+#endif
+
+    xmlNodePtr child_node = cur_node->xmlChildrenNode;
+    while (child_node) {
+        //parse <Value> tag
+        if (xmlStrcmp(child_node->name, (const xmlChar *)"Value") == 0) {
+            //allocate coefficient entry
+            APH_Coefficient *coeff_entry = (APH_Coefficient *)malloc(sizeof(APH_Coefficient));
+            if (coeff_entry == NULL) {
+                LOGE(_parse_coeff2, "%s/L%d: out of memory", __FUNCTION__, __LINE__);
+                free(coeff_configgroup_entry);
+                return -1;
+            }
+            memset(coeff_entry, 0, sizeof(APH_Coefficient));
+
+            xmlChar *value = xmlNodeListGetString(child_node->doc, child_node->xmlChildrenNode, 1);
+            if (value) {
+                coeff_entry->value = (unsigned char)strtoul((const char *)value, NULL, 16);
+                xmlFree(value);
+            }
+
+            //attach to coefficient list
+            if (coeff_configgroup_entry->coefficients == NULL) {
+                coeff_configgroup_entry->coefficients = coeff_entry;
+            } else {
+                APH_Coefficient *last_coeff = coeff_configgroup_entry->coefficients;
+                while (last_coeff->next) last_coeff = last_coeff->next;
+                last_coeff->next = coeff_entry;
+            }
+            coeff_configgroup_entry->coeff_value_number++;
+#ifdef DEBUG_XML_PARSER
+            LOGD(_parse_coeff3, "%s: <Value> value=0x%02x", __FUNCTION__, coeff_entry->value);
+#endif
+        }
+
+        child_node = child_node->next;
+    }
+
+    //add one coeff configuration into coeff configuration entry
+    if (coeff_config_entry->coefficients_group == NULL){
+        coeff_config_entry->coefficients_group  = coeff_configgroup_entry;
+    } else {
+        APH_Coefficient_Group *last_coeffgroup_config = coeff_config_entry->coefficients_group;
+        while (last_coeffgroup_config->next) last_coeffgroup_config = last_coeffgroup_config->next;
+        last_coeffgroup_config->next = coeff_configgroup_entry;
+    }
+
+    return 0;
+}
+
+static int _parse_eqcoeff(xmlNodePtr cur_node,
+    APH_EQCoeffConfigurationTable *table,
+    APH_BasicElementsTable *basic_info) {
+    //allocate coeff configuration group
+    APH_EQCoefficient *eq_coeff_entry = (APH_EQCoefficient*)malloc(sizeof(APH_EQCoefficient));
+    if (eq_coeff_entry == NULL) {
+        LOGE(_parse_eqcoeff, "%s/L%d: out of memory", __FUNCTION__, __LINE__);
+        return -1;
+    }
+    memset(eq_coeff_entry, 0, sizeof(APH_EQCoefficient));
+
+    //parse <Coeff> tag
+    xmlChar *coeff_name = xmlGetProp(cur_node, (const xmlChar *)"name");
+    eq_coeff_entry->coeff_id = _get_ctl_unit_id(coeff_name, basic_info);
+    xmlFree(coeff_name);
+
+#ifdef DEBUG_XML_PARSER
+    LOGD(_parse_eqcoeff1, "%s: <Coeff> coeff_name=%s", __FUNCTION__,
+        _get_ctl_unit_name(eq_coeff_entry->coeff_id, basic_info));
+#endif
+
+    xmlNodePtr child_node = cur_node->xmlChildrenNode;
+    while (child_node) {
+        //parse <Register> tag
+        if (xmlStrcmp(child_node->name, (const xmlChar *)"Register") == 0) {
+            if (eq_coeff_entry->coeff_filt_addr == NULL){
+                eq_coeff_entry->coeff_filt_addr = _parse_register(child_node, basic_info);
+            } else if (eq_coeff_entry->coeff_mngr == NULL){
+                eq_coeff_entry->coeff_mngr = _parse_register(child_node, basic_info);
+            } else {
+                APH_ControlUnitConfiguration *coeff_mngr_tmp = _parse_register(child_node, basic_info);
+                // attach to end of coeff_mngr
+                APH_ControlUnitConfiguration *last_coeff_mngr = eq_coeff_entry->coeff_mngr;
+                while (last_coeff_mngr->next) last_coeff_mngr = last_coeff_mngr->next;
+                last_coeff_mngr->next = coeff_mngr_tmp;
+            }
+        }
+        //parse <Value> tag
+        if (xmlStrcmp(child_node->name, (const xmlChar *)"Value") == 0) {
+            if (eq_coeff_entry->eq_coeff == NULL){
+                APH_ControlUnitConfiguration *ctl_unit_entry =
+                    (APH_ControlUnitConfiguration *)malloc(sizeof(APH_ControlUnitConfiguration));
+                if (ctl_unit_entry == NULL){
+                    LOGE(_parse_eqcoeff2, "%s/L%d: out of memory", __FUNCTION__, __LINE__);
+                    free(eq_coeff_entry);
+                    return -1;
+                }
+                memset(ctl_unit_entry, 0, sizeof(APH_ControlUnitConfiguration));
+                eq_coeff_entry->eq_coeff = ctl_unit_entry;
+
+                eq_coeff_entry->eq_coeff->i2c_unit.reg_value = (unsigned char *)malloc(xmlChildElementCount(cur_node));
+                //initialize eq_coeff_entry->eq_coeff
+                xmlChar *field = xmlGetProp(cur_node, (const xmlChar *)"name");
+                if (field) {
+                    ctl_unit_entry->control_unit_id = _get_ctl_unit_id(field, basic_info);
+                    APH_RegisterInfo *reg_info = basic_info->reg_info;
+                    while (reg_info) {
+                        if (strcmp((char *)reg_info->field, (const char *)field) == 0) {
+                            ctl_unit_entry->i2c_unit.reg_index = reg_info->index;
+                            ctl_unit_entry->i2c_unit.reg_mask = reg_info->field_mask;
+                            ctl_unit_entry->i2c_unit.reg_shift = reg_info->field_shift;
+                            ctl_unit_entry->i2c_unit.reg_type = reg_info->field_type;
+                            break;
+                        }
+                        reg_info = reg_info->next;
+                    }
+                    xmlFree(field);
+                }
+            }
+
+            xmlChar *value = xmlNodeListGetString(child_node->doc, child_node->xmlChildrenNode, 1);
+            int length = ++eq_coeff_entry->eq_coeff->i2c_unit.length;
+            //realloc(eq_coeff_entry->eq_coeff->i2c_unit.reg_value, length);
+            if (value) {
+                eq_coeff_entry->eq_coeff->i2c_unit.reg_value[length-1] = (unsigned char)strtoul((const char *)value, NULL, 16);
+                xmlFree(value);
+            }
+        }
+
+        child_node = child_node->next;
+    }
+
+    //add one eqcoeff configuration into eqcoeff configuration table
+    if (table->eq_coeff_configuration == NULL){
+        table->eq_coeff_configuration = eq_coeff_entry;
+    } else {
+        APH_EQCoefficient *last_eqcoeff = table->eq_coeff_configuration;
+        while (last_eqcoeff->next) last_eqcoeff = last_eqcoeff->next;
+        last_eqcoeff->next = eq_coeff_entry;
+    }
+
+    return 0;
+}
+
+static int _parse_coeff_path(xmlNodePtr cur_node,
+    APH_CoeffConfigurationTable *table,
+    APH_BasicElementsTable *basic_info,
+    APH_PathConfigurationTable *path_info,
+    xmlChar *path_identifier, xmlChar *component, xmlChar *op_identifier) {
+    //allocate coeff configuration entry
+    APH_CoeffConfiguration *coeff_config_entry = (APH_CoeffConfiguration *)malloc(sizeof(APH_CoeffConfiguration));
+    if (coeff_config_entry == NULL) {
+        LOGE(_parse_coeff_path, "%s/L%d: out of memory", __FUNCTION__, __LINE__);
+        return -1;
+    }
+    memset(coeff_config_entry, 0, sizeof(APH_CoeffConfiguration));
+
+    //get path id
+    coeff_config_entry->path_id = _get_path_id(path_identifier, path_info);
+
+    //get component id
+    coeff_config_entry->component_id = COMPONENT_STR2ENUM(component);
+
+    //get operation id
+    coeff_config_entry->path_op_id = OPERATION_STR2ENUM(op_identifier);
+
+#ifdef DEBUG_XML_PARSER
+    LOGD(_parse_coeff_path1, "%s: <Coeff> path_identifier=%s component_identifier=%s operation=%s\n",
+        __FUNCTION__,
+        _get_path_identifier(coeff_config_entry->path_id, path_info),
+        COMPONENT_ENUM2STR(coeff_config_entry->component_id),
+        OPERATION_ENUM2STR(coeff_config_entry->path_op_id));
+#endif
+
+    xmlNodePtr child_node = cur_node->xmlChildrenNode;
+    while (child_node) {
+        if (xmlStrcmp(child_node->name, (const xmlChar *)"Coeff") == 0) {
+            //parse <Coeff> tag
+            _parse_coeff(child_node, coeff_config_entry, basic_info, path_info);
+            coeff_config_entry->coeff_group_number++;
+        }
+
+        child_node = child_node->next;
+    }
+
+    //add one coeff configuration into coeff configuration table
+    if (table->coeff_configuration == NULL) {
+        table->coeff_configuration = coeff_config_entry;
+    } else {
+        APH_CoeffConfiguration *last_coeff_config = table->coeff_configuration;
+        while (last_coeff_config->next) last_coeff_config = last_coeff_config->next;
+        last_coeff_config->next = coeff_config_entry;
+    }
+    table->coeff_number++;
+
+    return 0;
+}
+
+static int _parse_equalizer(xmlNodePtr cur_node,
+    APH_EQCoeffConfigurationTable *table,
+    APH_BasicElementsTable *basic_info) {
+
+    //get component id
+    xmlChar *component = xmlGetProp(cur_node, (const xmlChar *)"component");
+    table->component_id = COMPONENT_STR2ENUM(component);
+    xmlFree(component);
+
+    //get control protocol
+    xmlChar *control_protocol = xmlGetProp(cur_node, (const xmlChar *)"control_protocol");
+    table->component_ctl_protocol = PROTOCOL_STR2ENUM(control_protocol);
+    xmlFree(control_protocol);
+
+#ifdef DEBUG_XML_PARSER
+    LOGD(_parse_equalizer, "%s: <Coeff> component_identifier=%s control_protocol=%s\n",
+        __FUNCTION__,
+        COMPONENT_ENUM2STR(table->component_id),
+        PROTOCOL_ENUM2STR(table->component_ctl_protocol));
+#endif
+
+    xmlNodePtr child_node = cur_node->xmlChildrenNode;
+    while (child_node) {
+        if (xmlStrcmp(child_node->name, (const xmlChar *)"Coeff") == 0) {
+            //parse <Coeff> tag
+            _parse_eqcoeff(child_node, table, basic_info);
+            table->eq_coeff_number++;
+        }
+
+        child_node = child_node->next;
+    }
+
+    return 0;
+}
+
+//--------------------------------------------------------------
+//-------- External XML Parsing APIs
+//--------------------------------------------------------------
+APH_BasicElementsTable *parse_basic_elements(const char *xml_file_name) {
+    xmlDocPtr doc;
+    xmlNodePtr cur_node;
+    APH_BasicElementsTable *table;
+    control_unit_id = INVALID_CTL_UNIT_ID + 1;
+
+    doc = xmlParseFile(xml_file_name);
+    if (doc == NULL) {
+        LOGE(parse_basic_elements, "%s: failed to parse xml file %s", __FUNCTION__, xml_file_name);
+        return NULL;
+    }
+
+    cur_node = xmlDocGetRootElement(doc);
+    if (cur_node == NULL) {
+        LOGE(parse_basic_elements1, "%s: failed to get root element in %s", __FUNCTION__, xml_file_name);
+        xmlFreeDoc(doc);
+        return NULL;
+    }
+
+    if (xmlStrcmp(cur_node->name, (const xmlChar *)"MarvellAudioBasicElements")) {
+        LOGE(parse_basic_elements2, "%s: wrong type document, root node != MarvellAudioBasicElements", __FUNCTION__);
+        xmlFreeDoc(doc);
+        return NULL;
+    }
+
+    //allocate APH basic elements table
+    table = (APH_BasicElementsTable *)malloc(sizeof(APH_BasicElementsTable));
+    if (table == NULL) {
+        LOGE(parse_basic_elements3, "%s/L%d: out of memory", __FUNCTION__, __LINE__);
+        xmlFreeDoc(doc);
+        return NULL;
+    }
+    memset(table, 0, sizeof(APH_BasicElementsTable));
+
+    //now walk the tree
+    cur_node = cur_node->xmlChildrenNode;
+    while (cur_node && xmlIsBlankNode(cur_node)) {
+        cur_node = cur_node->next;
+    }
+
+    if (cur_node == NULL) {
+        xmlFreeDoc(doc);
+        free(table);
+        return NULL;
+    }
+
+    while (cur_node) {
+        //parse <Version> tag
+        if (xmlStrcmp(cur_node->name, (const xmlChar *)"Version") == 0) {
+            xmlChar *version = xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1);
+            if (version) {
+#ifdef DEBUG_XML_PARSER
+                LOGD(parse_basic_elements4, "%s: <Version> %s", __FUNCTION__, version);
+#endif
+                char *ver_1, *ver_2;
+                ver_1 = strtok((char *)version, ".");
+                ver_2 = strtok(NULL, ".");
+                if (ver_1 && ver_2) {
+                    table->version = ((atoi(ver_1)) | (atoi(ver_2) << 8));
+                }
+                xmlFree(version);
+            }
+
+            cur_node = cur_node->next;
+            continue;
+        }
+
+        //search <Component> tag
+        if (xmlStrcmp(cur_node->name, (const xmlChar *)"Component")) {
+#ifdef DEBUG_XML_PARSER
+            if (!xmlNodeIsText(cur_node)) LOGD(parse_basic_elements5, "%s: skip tag <%s>", __FUNCTION__, cur_node->name);
+#endif
+            cur_node = cur_node->next;
+            continue;
+        }
+
+        //parse <Component> tag
+        xmlNodePtr child_node = cur_node->xmlChildrenNode;
+        while (child_node) {
+            if (xmlStrcmp(child_node->name, (const xmlChar *)"RegisterInfo") == 0) {
+                //parse <RegisterInfo> tag
+                _parse_register_info(child_node, table);
+            } else if (xmlStrcmp(child_node->name, (const xmlChar *)"HCIInfo") == 0) {
+                //parse <HCIInfo> tag
+                _parse_hci_info(child_node, table);
+            } else if (xmlStrcmp(child_node->name, (const xmlChar *)"GPIOInfo") == 0) {
+                //parse <GPIOInfo> tag
+                _parse_gpio_info(child_node, table);
+            }
+
+            child_node = child_node->next;
+        }
+
+        cur_node = cur_node->next;
+    }
+
+    xmlFreeDoc(doc);
+    return table;
+}
+
+extern int is_gssp_record_mode_support();
+APH_PathConfigurationTable *parse_path_configuration(const char *xml_file_name, APH_BasicElementsTable *basic_info) {
+    xmlDocPtr doc;
+    xmlNodePtr cur_node;
+    xmlNodePtr root_node;
+    APH_PathConfigurationTable *table;
+
+    // check gssp record mode
+    gssp_record = is_gssp_record_mode_support();
+
+    doc = xmlParseFile(xml_file_name);
+    if (doc == NULL) {
+        LOGE(parse_path_configuration, "%s: failed to parse xml file %s", __FUNCTION__, xml_file_name);
+        return NULL;
+    }
+
+    cur_node = xmlDocGetRootElement(doc);
+    if (cur_node == NULL) {
+        LOGE(parse_path_configuration1, "%s: failed to get root element in %s", __FUNCTION__, xml_file_name);
+        xmlFreeDoc(doc);
+        return NULL;
+    }
+
+    if (xmlStrcmp(cur_node->name, (const xmlChar *)"MarvellAudioPathConfiguration")) {
+        LOGE(parse_path_configuration2, "%s: wrong type document, root node != MarvellAudioPathConfiguration", __FUNCTION__);
+        xmlFreeDoc(doc);
+        return NULL;
+    }
+
+    //allocate APH path configuration table
+    table = (APH_PathConfigurationTable *)malloc(sizeof(APH_PathConfigurationTable));
+    if (table == NULL) {
+        LOGE(parse_path_configuration3, "%s/L%d: out of memory", __FUNCTION__, __LINE__);
+        xmlFreeDoc(doc);
+        return NULL;
+    }
+    memset(table, 0, sizeof(APH_PathConfigurationTable));
+
+    //now walk the tree
+    cur_node = cur_node->xmlChildrenNode;
+    while (cur_node && xmlIsBlankNode(cur_node)) {
+        cur_node = cur_node->next;
+    }
+
+    if (cur_node == NULL) {
+        xmlFreeDoc(doc);
+        free(table);
+        return NULL;
+    }
+
+    root_node = cur_node;
+    //map path identifer to path id firstly
+    _map_path_identifier(cur_node, table);
+
+    while (cur_node) {
+        //search <AudioPath> tag
+        if (xmlStrcmp(cur_node->name, (const xmlChar *)"AudioPath")) {
+#ifdef DEBUG_XML_PARSER
+            if (!xmlNodeIsText(cur_node)) LOGD(parse_path_configuration4, "%s: skip tag <%s>", __FUNCTION__, cur_node->name);
+#endif
+            cur_node = cur_node->next;
+            continue;
+        }
+
+        //get alias attribute
+        xmlChar *alias = xmlGetProp(cur_node, (const xmlChar *)"alias");
+        xmlChar *path_identifier = xmlGetProp(cur_node, (const xmlChar *)"identifier");
+        xmlNodePtr child_node = NULL;
+        if (alias != NULL){
+            xmlNodePtr search_node = root_node;
+            //search the alias destination path node
+            while (search_node)
+            {
+                xmlChar *path_identifier_t = xmlGetProp(search_node, (const xmlChar *)"identifier");
+                if (xmlStrcmp(search_node->name, (const xmlChar *)"AudioPath") == 0 &&
+                    xmlStrcmp(path_identifier_t, alias) == 0){
+                    xmlFree(path_identifier_t);
+                    path_identifier_t = NULL;
+
+                    // multiple alias check
+                    xmlChar *alias_t = xmlGetProp(search_node, (const xmlChar *)"alias");
+                    if (!alias_t) {
+                        break;
+                    } else {
+                        xmlFree(alias);
+                        alias = alias_t;
+                    }
+                    search_node = root_node;
+                    continue;
+                }
+                if (path_identifier_t){
+                    xmlFree(path_identifier_t);
+                    path_identifier_t = NULL;
+                }
+                search_node = search_node->next;
+            }
+
+            if (search_node) {
+                child_node = search_node->xmlChildrenNode;
+            }
+        } else {
+            child_node = cur_node->xmlChildrenNode;
+        }
+
+        //parse <AudioPath> tag
+        while (child_node) {
+            if (xmlStrcmp(child_node->name, (const xmlChar *)"Operation") == 0) {
+                //parse <Operation> tag
+                _parse_operation(child_node, table, basic_info, path_identifier);
+            }
+            child_node = child_node->next;
+        }
+        xmlFree(path_identifier);
+        if (alias){
+            xmlFree(alias);
+            alias = NULL;
+        }
+
+        cur_node = cur_node->next;
+    }
+
+    xmlFreeDoc(doc);
+    return table;
+}
+
+APH_GainConfigurationTable *parse_gain_configuration(const char *xml_file_name,
+    APH_BasicElementsTable *basic_info,
+    APH_PathConfigurationTable *path_info) {
+    xmlDocPtr doc;
+    xmlNodePtr cur_node;
+    xmlNodePtr root_node;
+    APH_GainConfigurationTable *table;
+
+    doc = xmlParseFile(xml_file_name);
+    if (doc == NULL) {
+        LOGE(parse_gain_configuration, "%s: failed to parse xml file %s", __FUNCTION__, xml_file_name);
+        return NULL;
+    }
+
+    cur_node = xmlDocGetRootElement(doc);
+    if (cur_node == NULL) {
+        LOGE(parse_gain_configuration1, "%s: failed to get root element in %s", __FUNCTION__, xml_file_name);
+        xmlFreeDoc(doc);
+        return NULL;
+    }
+
+    if (xmlStrcmp(cur_node->name, (const xmlChar *)"MarvellAudioGainConfiguration")) {
+        LOGE(parse_gain_configuration2, "%s: wrong type document, root node != MarvellAudioGainConfiguration", __FUNCTION__);
+        xmlFreeDoc(doc);
+        return NULL;
+    }
+
+    //allocate APH gain configuration table
+    table = (APH_GainConfigurationTable *)malloc(sizeof(APH_GainConfigurationTable));
+    if (table == NULL) {
+        LOGE(parse_gain_configuration3, "%s/L%d: out of memory", __FUNCTION__, __LINE__);
+        xmlFreeDoc(doc);
+        return NULL;
+    }
+    memset(table, 0, sizeof(APH_GainConfigurationTable));
+
+    //now walk the tree
+    cur_node = cur_node->xmlChildrenNode;
+    while (cur_node && xmlIsBlankNode(cur_node)) {
+        cur_node = cur_node->next;
+    }
+
+    if (cur_node == NULL) {
+        xmlFreeDoc(doc);
+        free(table);
+        return NULL;
+    }
+    root_node = cur_node;
+    while (cur_node) {
+        //search <AudioPath> tag
+        if (xmlStrcmp(cur_node->name, (const xmlChar *)"AudioPath")) {
+#ifdef DEBUG_XML_PARSER
+            if (!xmlNodeIsText(cur_node)) LOGD(parse_gain_configuration5, "%s: skip tag <%s>", __FUNCTION__, cur_node->name);
+#endif
+            cur_node = cur_node->next;
+            continue;
+        }
+
+        //get alias attribute
+        xmlChar *alias = xmlGetProp(cur_node, (const xmlChar *)"alias");
+        xmlChar *path_identifier = xmlGetProp(cur_node, (const xmlChar *)"identifier");
+        xmlChar *component = xmlGetProp(cur_node, (const xmlChar *)"component");
+        xmlNodePtr child_node = NULL;
+        if (alias != NULL){
+            xmlNodePtr search_node = root_node;
+            //search the alias destination path node
+            while (search_node)
+            {
+                xmlChar *path_identifier_t = xmlGetProp(search_node, (const xmlChar *)"identifier");
+                xmlChar *component_t = xmlGetProp(search_node, (const xmlChar *)"component");
+                if (xmlStrcmp(search_node->name, (const xmlChar *)"AudioPath") == 0 &&
+                    xmlStrcmp(path_identifier_t, alias) == 0 &&
+                    xmlStrcmp(component_t, component) == 0) {
+                    xmlFree(path_identifier_t);
+                    path_identifier_t = NULL;
+                    xmlFree(component_t);
+                    component_t = NULL;
+
+                    // multiple alias check
+                    xmlChar *alias_t = xmlGetProp(search_node, (const xmlChar *)"alias");
+                    if (!alias_t) {
+                        break;
+                    } else {
+                       xmlFree(alias);
+                       alias = alias_t;
+                    }
+                    search_node = root_node;
+                    continue;
+                }
+                if (path_identifier_t){
+                    xmlFree(path_identifier_t);
+                    path_identifier_t = NULL;
+                }
+                if (component_t){
+                    xmlFree(component_t);
+                    component_t = NULL;
+                }
+                search_node = search_node->next;
+            }
+
+            if (search_node) {
+                child_node = search_node->xmlChildrenNode;
+            }
+        } else {
+            child_node = cur_node->xmlChildrenNode;
+        }
+
+
+        //parse <AudioPath> tag
+        while (child_node) {
+            if (xmlStrcmp(child_node->name, (const xmlChar *)"Gain") == 0) {
+                //parse <Gain> tag
+                _parse_gain(child_node, table, basic_info, path_info, path_identifier, component);
+            }
+
+            child_node = child_node->next;
+        }
+        xmlFree(path_identifier);
+        xmlFree(component);
+        if (alias) {
+            xmlFree(alias);
+            alias = NULL;
+	}
+
+        cur_node = cur_node->next;
+    }
+
+    xmlFreeDoc(doc);
+    return table;
+}
+
+APH_CoeffConfigurationTable *parse_coeff_configuration(const char *xml_file_name,
+    APH_BasicElementsTable *basic_info,
+    APH_PathConfigurationTable *path_info) {
+    xmlDocPtr doc;
+    xmlNodePtr cur_node;
+    xmlNodePtr root_node;
+    APH_CoeffConfigurationTable *table;
+
+    doc = xmlParseFile(xml_file_name);
+    if (doc == NULL) {
+        LOGE(parse_coeff_configuration, "%s: failed to parse xml file %s", __FUNCTION__, xml_file_name);
+        return NULL;
+    }
+
+    cur_node = xmlDocGetRootElement(doc);
+    if (cur_node == NULL) {
+        LOGE(parse_coeff_configuration1, "%s: failed to get root element in %s", __FUNCTION__, xml_file_name);
+        xmlFreeDoc(doc);
+        return NULL;
+    }
+
+    if (xmlStrcmp(cur_node->name, (const xmlChar *)"MarvellAudioCoeffConfiguration")) {
+        LOGE(parse_coeff_configuration2, "%s: wrong type document, root node != MarvellAudioCoeffConfiguration", __FUNCTION__);
+        xmlFreeDoc(doc);
+        return NULL;
+    }
+
+    //allocate APH coeff configuration table
+    table = (APH_CoeffConfigurationTable *)malloc(sizeof(APH_CoeffConfigurationTable));
+    if (table == NULL) {
+        LOGE(parse_coeff_configuration3, "%s/L%d: out of memory", __FUNCTION__, __LINE__);
+        xmlFreeDoc(doc);
+        return NULL;
+    }
+    memset(table, 0, sizeof(APH_CoeffConfigurationTable));
+
+    //now walk the tree
+    cur_node = cur_node->xmlChildrenNode;
+    while (cur_node && xmlIsBlankNode(cur_node)) {
+        cur_node = cur_node->next;
+    }
+
+    if (cur_node == NULL) {
+        xmlFreeDoc(doc);
+        free(table);
+        return NULL;
+    }
+
+    root_node = cur_node;
+    while (cur_node) {
+        //search <AudioPath> tag
+        if (xmlStrcmp(cur_node->name, (const xmlChar *)"AudioPath")) {
+#ifdef DEBUG_XML_PARSER
+            if (!xmlNodeIsText(cur_node)) LOGD(parse_coeff_configuration4, "%s: skip tag <%s>", __FUNCTION__, cur_node->name);
+#endif
+            cur_node = cur_node->next;
+            continue;
+        }
+
+        //get alias attribute
+        xmlChar *alias = xmlGetProp(cur_node, (const xmlChar *)"alias");
+        xmlChar *path_identifier = xmlGetProp(cur_node, (const xmlChar *)"identifier");
+        xmlChar *component = xmlGetProp(cur_node, (const xmlChar *)"component");
+        xmlChar *operation = xmlGetProp(cur_node, (const xmlChar *)"operation");
+        xmlNodePtr alias_node = NULL;
+        if (alias != NULL) {
+            xmlNodePtr search_node = root_node;
+            //search the alias destination path node
+            while (search_node)
+            {
+                xmlChar *path_identifier_t = xmlGetProp(search_node, (const xmlChar *)"identifier");
+                xmlChar *component_t = xmlGetProp(search_node, (const xmlChar *)"component");
+                xmlChar *operation_t = xmlGetProp(search_node, (const xmlChar *)"operation");
+                if (xmlStrcmp(search_node->name, (const xmlChar *)"AudioPath") == 0 &&
+                    xmlStrcmp(path_identifier_t, alias) == 0 &&
+                    xmlStrcmp(component_t, component) == 0 &&
+                    xmlStrcmp(operation_t, operation) == 0) {
+                    xmlChar *alias_t = xmlGetProp(search_node, (const xmlChar *)"alias");
+                    xmlFree(path_identifier_t);
+                    path_identifier_t = NULL;
+                    xmlFree(component_t);
+                    component_t = NULL;
+                    xmlFree(operation_t);
+                    operation_t = NULL;
+
+                    // multiple alias check
+                    if (!alias_t) {
+                        break;
+                    } else {
+                        xmlFree(alias);
+                        alias = alias_t;
+                    }
+                    search_node = root_node;
+                    continue;
+                }
+                if (path_identifier_t){
+                    xmlFree(path_identifier_t);
+                    path_identifier_t = NULL;
+                }
+                if (component_t){
+                    xmlFree(component_t);
+                    component_t = NULL;
+                }
+                if (operation_t){
+                    xmlFree(operation_t);
+                    operation_t = NULL;
+                }
+                search_node = search_node->next;
+            }
+
+            if (search_node) {
+                alias_node = search_node;
+            }
+        } else {
+            alias_node = cur_node;
+        }
+
+        //parse each coefficient path
+        if (alias_node) {
+            _parse_coeff_path(alias_node, table, basic_info, path_info, path_identifier, component, operation);
+        }
+        xmlFree(path_identifier);
+        xmlFree(component);
+        xmlFree(operation);
+        if (alias) {
+            xmlFree(alias);
+            alias = NULL;
+        }
+        cur_node = cur_node->next;
+    }
+
+    xmlFreeDoc(doc);
+    return table;
+}
+
+APH_EQCoeffConfigurationTable *parse_eqcoeff_configuration(const char *xml_file_name,
+    APH_BasicElementsTable *basic_info) {
+    xmlDocPtr doc;
+    xmlNodePtr cur_node;
+    APH_EQCoeffConfigurationTable *table;
+
+    doc = xmlParseFile(xml_file_name);
+    if (doc == NULL) {
+        LOGE(parse_eqcoeff_configuration, "%s: failed to parse xml file %s", __FUNCTION__, xml_file_name);
+        return NULL;
+    }
+
+    cur_node = xmlDocGetRootElement(doc);
+    if (cur_node == NULL) {
+        LOGE(parse_eqcoeff_configuration1, "%s: failed to get root element in %s", __FUNCTION__, xml_file_name);
+        xmlFreeDoc(doc);
+        return NULL;
+    }
+
+    if (xmlStrcmp(cur_node->name, (const xmlChar *)"MarvellAudioCoeffConfiguration")) {
+        LOGE(parse_eqcoeff_configuration2, "%s: wrong type document, root node != MarvellAudioCoeffConfiguration", __FUNCTION__);
+        xmlFreeDoc(doc);
+        return NULL;
+    }
+
+    //allocate APH coeff configuration table
+    table = (APH_EQCoeffConfigurationTable *)malloc(sizeof(APH_EQCoeffConfigurationTable));
+    if (table == NULL) {
+        LOGE(parse_eqcoeff_configuration3, "%s/L%d: out of memory", __FUNCTION__, __LINE__);
+        xmlFreeDoc(doc);
+        return NULL;
+    }
+    memset(table, 0, sizeof(APH_EQCoeffConfigurationTable));
+
+    //now walk the tree
+    cur_node = cur_node->xmlChildrenNode;
+    while (cur_node && xmlIsBlankNode(cur_node)) {
+        cur_node = cur_node->next;
+    }
+
+    if (cur_node == NULL) {
+        xmlFreeDoc(doc);
+        free(table);
+        return NULL;
+    }
+
+    while (cur_node) {
+        //search <Equalizer> tag
+        if (xmlStrcmp(cur_node->name, (const xmlChar *)"Equalizer")) {
+#ifdef DEBUG_XML_PARSER
+            if (!xmlNodeIsText(cur_node)) LOGD(parse_eqcoeff_configuration4, "%s: skip tag <%s>", __FUNCTION__, cur_node->name);
+#endif
+            cur_node = cur_node->next;
+            continue;
+        }
+
+        //parse equalizer
+        _parse_equalizer(cur_node, table, basic_info);
+        break;
+    }
+
+    xmlFreeDoc(doc);
+    return table;
+}
diff --git a/marvell/services/audio/libacm/acm/src/audio_dsp.c b/marvell/services/audio/libacm/acm/src/audio_dsp.c
new file mode 100644
index 0000000..9298e37
--- /dev/null
+++ b/marvell/services/audio/libacm/acm/src/audio_dsp.c
@@ -0,0 +1,299 @@
+/******************************************************************************
+*
+*  (C)Copyright 2022 ASRMicro. All Rights Reserved.
+*
+*  THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ASRMicro.
+*  The copyright notice above does not evidence any actual or intended
+*  publication of such source code.
+*  This Module contains Proprietary Information of ASRMicro and should be
+*  treated as Confidential.
+*  The information in this file is provided for the exclusive use of the
+*  licensees of ASRMicro.
+*  Such users have the right to use, modify, and incorporate this code into
+*  products for purposes authorized by the license agreement provided they
+*  include this notice and the associated copyright notice with any such
+*  product.
+*  The information in this file is provided "AS IS" without warranty.
+*
+******************************************************************************/
+
+
+/******************************************************************************
+*               MODULE IMPLEMENTATION FILE
+*******************************************************************************
+* Title: APIs in user space for ADSP in AP subsystem
+*
+* Filename: audio_dsp.h
+*
+* Authors: Yjg Wang
+*
+* Description: ADSP APIs in user space.
+*
+* Last Updated:
+*
+* Notes:
+******************************************************************************/
+
+
+/******************************************************************************
+*   Include files
+******************************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <cutils/log.h>
+#include "adsp_ve.h"
+#include "audio_dsp.h"
+
+
+/******************************************************************************
+*   Macro definitions
+******************************************************************************/
+#define AUDIO_DSP_MAGIC 'y'
+#define ADSP_ENABLE _IO(AUDIO_DSP_MAGIC, 0x00)
+#define ADSP_DISABLE _IO(AUDIO_DSP_MAGIC, 0x01)
+#define ADSP_SET _IOW(AUDIO_DSP_MAGIC, 0x02, uint16_t[ADSP_SET_COMMAND_LENGTH])
+#define ADSP_SEND_VE _IOW(AUDIO_DSP_MAGIC, 0x03, EnhanceParmsT)
+#define ADSP_DUMP_FULL_DDR _IOR(AUDIO_DSP_MAGIC, 0x4, uint32_t)
+#define ADSP_START_AUDIO_PATH _IOW(AUDIO_DSP_MAGIC, 0x05, uint16_t[VOICE_START_COMMAND_LENGTH + 2])
+#define ADSP_END_AUDIO_PATH _IOW(AUDIO_DSP_MAGIC, 0x06, uint16_t[4])
+
+
+/******************************************************************************
+*   Local variable definitions
+******************************************************************************/
+static int audio_dsp_fd = -1;
+static int _vpathActive = 0;
+
+
+/******************************************************************************
+*   function definitions
+******************************************************************************/
+#if 0
+//Just for the cmds which cmdLength == 0
+static int IPCCommCommandSend(IPC_Command *cmd, unsigned int request)
+{
+    if (!cmd) {
+        LOGI(IPCCommCommandSend, "audio_dsp %s:%s:%d, type=%d is incorrect\n", __FILE__, __FUNCTION__, __LINE__);
+        return -1;
+    }
+
+    if (audio_dsp_fd > 0) {
+        LOGI(IPCCommCommandSend, "audio_dsp %s:%s:%d, opCode=%s\n", __FILE__, __FUNCTION__, __LINE__, cmd->opCode);
+
+        return ioctl(audio_dsp_fd, request, cmd);
+    }
+
+    LOGI(IPCCommCommandSend, "audio_dsp %s:%s:%d, device not ready, fd=%d\n", __FILE__, __FUNCTION__, __LINE__, audio_dsp_fd);
+    return -2;
+}
+#endif
+
+int audio_dsp_init(void)
+{
+    if (audio_dsp_fd <= 0) {
+        audio_dsp_fd = open("/dev/audio_dsp", O_RDWR);
+        if (audio_dsp_fd <= 0) {
+            LOGI(audio_dsp_init, "audio_dsp %s:%s:%d, open device fail, fd=%d\n", __FILE__, __FUNCTION__, __LINE__, audio_dsp_fd);
+            return -1;
+        }
+
+        LOGI(audio_dsp_init, "audio_dsp %s:%s:%d, open device success, fd=%d\n", __FILE__, __FUNCTION__, __LINE__, audio_dsp_fd);
+
+#if 0
+        if (ioctl(audio_dsp_fd, ADSP_ENABLE)) {
+            return -2;
+        }
+#endif
+
+        return 0;
+    }
+
+    LOGI(audio_dsp_init, "audio_dsp %s:%s:%d, device already open\n", __FILE__, __FUNCTION__, __LINE__);
+    return -3;
+}
+
+int audio_dsp_enable(void)
+{
+    LOGI(audio_dsp_enable, "audio_dsp %s:%s:%d, device not ready, fd=%d\n", __FILE__, __FUNCTION__, __LINE__, audio_dsp_fd);
+    return -2;
+}
+
+int audio_dsp_disable(void)
+{
+    LOGI(audio_dsp_disable, "audio_dsp %s:%s:%d, device not ready, fd=%d\n", __FILE__, __FUNCTION__, __LINE__, audio_dsp_fd);
+    return -3;
+}
+
+void audio_dsp_exit(void)
+{
+    LOGI(audio_dsp_exit, "audio_dsp %s:%s:%d, fd=%d\n", __FILE__, __FUNCTION__, __LINE__, audio_dsp_fd);
+
+    if (audio_dsp_fd > 0) {
+        close(audio_dsp_fd);
+    }
+
+    audio_dsp_fd = -1;
+}
+
+int audio_dsp_set(char *cmd)
+{
+    unsigned short data[ADSP_SET_COMMAND_LENGTH] = { 0 };
+    char *p = cmd;
+    int i = 0, r, v, n;
+
+    if (audio_dsp_fd <= 0) {
+        LOGI(audio_dsp_set, "audio_dsp %s, just for ASR1901 A0, fd=%d\n", __FUNCTION__, audio_dsp_fd);
+        return 1;
+    }
+
+    while (1) {
+        r = sscanf(p, "%x %n", &v, &n);
+        if (1 == r) {
+            data[i++] = v;
+            p += n;
+        }
+        else if (0 == r) {
+            p++;
+        }
+        else {
+            break;
+        }
+    }
+
+    LOGI(audio_dsp_set, "%s/%d: |%.2x|%.2x|%.2x|%.2x|%.2x|%.2x|%.2x|%.2x\n", __FUNCTION__, __LINE__, \
+         data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);
+
+    if (ioctl(audio_dsp_fd, ADSP_SET, data)) {
+        return 2;
+    }
+
+    return 0;
+}
+
+int audio_dsp_send_ve(void *ve)
+{
+    LOGI(audio_dsp_send_ve, "%s/%d\n", __FUNCTION__, __LINE__);
+
+    if (audio_dsp_fd <= 0) {
+        LOGI(audio_dsp_send_ve, "audio_dsp %s, just for ASR1901 A0, fd=%d\n", __FUNCTION__, audio_dsp_fd);
+        return 1;
+    }
+
+    if (!ve) {
+        LOGI(audio_dsp_send_ve, "audio_dsp %s, vE is null\n", __FUNCTION__);
+        return 2;
+    }
+
+    if (ioctl(audio_dsp_fd, ADSP_SEND_VE, (EnhanceParmsT *)ve)) {
+        return 3;
+    }
+
+    return 0;
+}
+
+int audio_dsp_dump_full_ddr(unsigned int val)
+{
+    LOGI(audio_dsp_dump_full_ddr, "%s/%d\n", __FUNCTION__, __LINE__);
+
+    if (audio_dsp_fd <= 0) {
+        LOGI(audio_dsp_dump_full_ddr, "audio_dsp %s, just for ASR1901 A0, fd=%d\n", __FUNCTION__, audio_dsp_fd);
+        return 1;
+    }
+
+    if (val < 0 || val > 1) {
+        LOGI(audio_dsp_dump_full_ddr, "audio_dsp %s, val is invalid\n", __FUNCTION__);
+        return 2;
+    }
+
+    if (ioctl(audio_dsp_fd, ADSP_DUMP_FULL_DDR, &val)) {
+        return 3;
+    }
+
+    return 0;
+}
+
+int vpathStart(unsigned int voiceControl,
+               unsigned short voiceAuxMode,
+               unsigned short vocoderType,
+               unsigned short encoderMode,
+               unsigned short voiceTestControl,
+               unsigned short dtxFlag)
+{
+    //IPC_Command cmd;
+    unsigned short data[VOICE_START_COMMAND_LENGTH + 2] = { 0 };
+
+    if (audio_dsp_fd <= 0) {
+        LOGI(vpathStart, "audio_dsp %s, just for ASR1901 A0, fd=%d\n", __FUNCTION__, audio_dsp_fd);
+        return 1;
+    }
+
+    if (_vpathActive) {
+        LOGI(vpathStart, "_vpathActive is TRUE,do not send the 0x40 for multi times!");
+        return 2;
+    }
+
+    LOGI(vpathStart, "vpathStart; COMMS Audio Sleep OFF");
+
+    data[0] = START_VOICE_PATH;
+    data[1] = sizeof(data) / sizeof(UINT16);
+
+    data[2] = (voiceControl & 0xffff0000) >> 16;
+    data[3] = (voiceControl & 0x0000ffff);
+    data[4] = voiceAuxMode;
+    data[5] = vocoderType;
+    data[6] = encoderMode;
+    data[7] = voiceTestControl;
+    data[8] = dtxFlag;
+
+    LOGI(vpathStart, "vpathStart; voiceControl=0x%lx", voiceControl);
+
+    //cmd.opCode = START_VOICE_PATH;
+    //cmd.cmdLength = sizeof(data) / sizeof(UINT16);
+    //cmd.cmdData = data;
+
+    if (ioctl(audio_dsp_fd, ADSP_START_AUDIO_PATH, data)) {
+        return 3;
+    }
+
+    _vpathActive = 1;
+    return 0;
+
+}
+
+int vpathStop(void)
+{
+    //IPC_Command cmd;
+    unsigned short data[4] = { 0 };
+
+    if (audio_dsp_fd <= 0) {
+        LOGI(vpathStop, "audio_dsp %s, just for ASR1901 A0, fd=%d\n", __FUNCTION__, audio_dsp_fd);
+        return 1;
+    }
+
+    if (!_vpathActive) {
+        LOGI(vpathStop, "_vpathActive is FALSE,do not send the 0x41 for multi times!");
+        //return 2;
+    }
+
+    data[0] = END_VOICE_PATH;
+    data[1] = 0;
+
+    data[2] = (UINT16 *)0xffff; // This Field is no meanful, because static code tool said it should be init,so setting it to 0xffff--2014-07
+
+    //cmd.opCode = END_VOICE_PATH;
+    //cmd.cmdLength = 0;
+    //cmd.cmdData = (UINT16 *)0xffff; // This Field is no meanful, because static code tool said it should be init,so setting it to 0xffff--2014-07
+
+    if (ioctl(audio_dsp_fd, ADSP_END_AUDIO_PATH, data)) {
+        return 2;
+    }
+
+    _vpathActive = 0;
+    return 0;
+}
diff --git a/marvell/services/audio/libacm/acm/src/audio_pa.c b/marvell/services/audio/libacm/acm/src/audio_pa.c
new file mode 100644
index 0000000..7597396
--- /dev/null
+++ b/marvell/services/audio/libacm/acm/src/audio_pa.c
@@ -0,0 +1,143 @@
+/******************************************************************************
+*
+*  (C)Copyright 2022 ASRMicro. All Rights Reserved.
+*
+*  THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ASRMicro.
+*  The copyright notice above does not evidence any actual or intended
+*  publication of such source code.
+*  This Module contains Proprietary Information of ASRMicro and should be
+*  treated as Confidential.
+*  The information in this file is provided for the exclusive use of the
+*  licensees of ASRMicro.
+*  Such users have the right to use, modify, and incorporate this code into
+*  products for purposes authorized by the license agreement provided they
+*  include this notice and the associated copyright notice with any such
+*  product.
+*  The information in this file is provided "AS IS" without warranty.
+*
+******************************************************************************/
+
+
+/******************************************************************************
+*   Include files
+******************************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <cutils/log.h>
+#include "audio_pa.h"
+
+
+/******************************************************************************
+*   Macro definitions
+******************************************************************************/
+#define AUDIO_PA_MAGIC 'y'
+#define PA_ENABLE _IO(AUDIO_PA_MAGIC, 'a')
+#define PA_DISABLE _IO(AUDIO_PA_MAGIC, 'b')
+
+
+/******************************************************************************
+*   Local variable definitions
+******************************************************************************/
+static int audio_pa_fd = -1;
+static int is_in_voice = 0;
+static int is_in_media = 0;
+
+
+/******************************************************************************
+*   function definitions
+******************************************************************************/
+int audio_pa_init(void)
+{
+    if (audio_pa_fd <= 0) {
+        audio_pa_fd = open("/dev/audio_pa", O_RDWR);
+        if (audio_pa_fd <= 0) {
+            LOGI(audio_pa_init, "audio_pa %s:%s:%d, open device fail, fd=%d\n", __FILE__, __FUNCTION__, __LINE__, audio_pa_fd);
+            return -1;
+        }
+
+        LOGI(aaudio_pa_init, "audio_pa %s:%s:%d, open device success, fd=%d\n", __FILE__, __FUNCTION__, __LINE__, audio_pa_fd);
+        return 0;
+    }
+
+    LOGI(audio_pa_init, "audio_pa %s:%s:%d, device already open\n", __FILE__, __FUNCTION__, __LINE__);
+    return -2;
+}
+
+int audio_pa_enable(AUDIO_PA_TYPE type)
+{
+    if (type < AUDIO_PA_VOICE || type > AUDIO_PA_MEDIA) {
+        LOGI(audio_pa_enable, "audio_pa %s:%s:%d, type=%d is incorrect\n", __FILE__, __FUNCTION__, __LINE__);
+        ioctl(audio_pa_fd, PA_DISABLE);
+        return -1;
+    }
+
+    if (audio_pa_fd > 0) {
+        LOGI(audio_pa_enable, "audio_pa %s:%s:%d, in_voice=%s, in_media=%s, type=%s\n",
+             __FILE__, __FUNCTION__, __LINE__, is_in_voice?"yes":"no", is_in_media?"yes":"no", type == 1?"voice":"media");
+
+        if (!is_in_voice && !is_in_media) {
+            ioctl(audio_pa_fd, PA_ENABLE);
+        }
+
+        if (AUDIO_PA_VOICE == type && !is_in_voice) {
+            is_in_voice = 1;
+        }
+        else if (AUDIO_PA_MEDIA == type && !is_in_media) {
+            is_in_media = 1;
+        }
+
+        return 0;
+    }
+
+    LOGI(audio_pa_enable, "audio_pa %s:%s:%d, device not ready, fd=%d\n", __FILE__, __FUNCTION__, __LINE__, audio_pa_fd);
+    return -2;
+}
+
+int audio_pa_disable(AUDIO_PA_TYPE type)
+{
+    if (type < AUDIO_PA_VOICE || type > AUDIO_PA_MEDIA) {
+        LOGI(audio_pa_disable, "audio_pa %s:%s:%d, type=%d is incorrect\n", __FILE__, __FUNCTION__, __LINE__);
+        ioctl(audio_pa_fd, PA_DISABLE);
+        return -1;
+    }
+
+    if (audio_pa_fd > 0) {
+        LOGI(audio_pa_disable, "audio_pa %s:%s:%d, in_voice=%s, in_media=%s, type=%s\n",
+             __FILE__, __FUNCTION__, __LINE__, is_in_voice?"yes":"no", is_in_media?"yes":"no", type == 1?"voice":"media");
+
+        if (AUDIO_PA_VOICE == type && is_in_voice) {
+            is_in_voice = 0;
+        }
+        else if (AUDIO_PA_MEDIA == type && is_in_media) {
+            is_in_media = 0;
+        }
+        else {
+            return -2;
+        }
+
+        if (!is_in_voice && !is_in_media) {
+            ioctl(audio_pa_fd, PA_DISABLE);
+        }
+        return 0;
+    }
+
+    LOGI(audio_pa_disable, "audio_pa %s:%s:%d, device not ready, fd=%d\n", __FILE__, __FUNCTION__, __LINE__, audio_pa_fd);
+    return -3;
+}
+
+void audio_pa_exit(void)
+{
+    LOGI(audio_pa_exit, "audio_pa %s:%s:%d, fd=%d\n", __FILE__, __FUNCTION__, __LINE__, audio_pa_fd);
+
+    if (audio_pa_fd > 0) {
+        close(audio_pa_fd);
+    }
+
+    audio_pa_fd = -1;
+}