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(¶m);
+ }
+
+ 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(¶m);
+
+ //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(¶m);
+ }
+
+ 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(¶m);
+
+ 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(®_cache_inorder[k], ®_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(®_cache_inorder[k], ®_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(®_cache_inorder[k], ®_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;
+}