| /* |
| * 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 "audio_hw_path" |
| #define LOG_NDEBUG 0 |
| |
| #include <system/audio.h> |
| #include <cutils/log.h> |
| #include "audio_path.h" |
| #include "audio_hw_mrvl.h" |
| #include "acm_api.h" |
| #include "acm_param.h" |
| #include "audio_path.h" |
| #include "acm_aph.h" |
| |
| |
| // define the path device, include playback output and record input path |
| #define MAX_NUM_DEV (sizeof(gPathDevice)/sizeof(gPathDevice[0])) |
| static const struct |
| { |
| unsigned int device; |
| unsigned int flag; |
| char* apu_path; |
| char* codec_path; |
| }gPathDevice[] = |
| { |
| #ifdef PXA1826_AUDIO ////Enable virtual path |
| // output devices |
| {HWDEV_EARPIECE, 0, PATH_NAME(ToEarpiece), PATH_NAME(Earpiece)}, |
| {HWDEV_SPEAKER, 0, PATH_NAME(ToSpeaker), PATH_NAME(Speaker)}, |
| {HWDEV_STEREOSPEAKER, 0, PATH_NAME(ToStereoSpeaker), PATH_NAME(StereoSpeaker)}, |
| {HWDEV_HEADPHONE, 0, PATH_NAME(ToHeadphone), PATH_NAME(Headphone)}, |
| {HWDEV_BLUETOOTH_NB, 0, PATH_NAME(ToBTNB), NULL}, |
| {HWDEV_BT_NREC_OFF_NB, 0, PATH_NAME(ToBTNB(NREC Mode)), NULL}, |
| {HWDEV_BLUETOOTH_WB, 0, PATH_NAME(ToBTWB), NULL}, |
| {HWDEV_BT_NREC_OFF_WB, 0, PATH_NAME(ToBTWB(NREC Mode)), NULL}, |
| {HWDEV_OUT_TTY, 0, PATH_NAME(ToHeadphone), PATH_NAME(Headphone)}, |
| {HWDEV_OUT_TTY_HCO_SPEAKER, 0, PATH_NAME(ToSpeaker), PATH_NAME(Speaker)}, |
| {HWDEV_OUT_TTY_HCO_STEREOSPEAKER, 0, PATH_NAME(ToStereoSpeaker), PATH_NAME(StereoSpeaker)}, |
| |
| // input devices |
| {HWDEV_AMIC1, 0, PATH_NAME(FromAMic1), PATH_NAME(AMic1)}, |
| {HWDEV_AMIC1_SPK_MODE, 0, PATH_NAME(FromAMic1(Speaker Mode)), PATH_NAME(AMic1(Speaker Mode))}, |
| {HWDEV_AMIC2, 0, PATH_NAME(FromAMic2), PATH_NAME(AMic2)}, |
| {HWDEV_AMIC2_SPK_MODE, 0, PATH_NAME(FromAMic2(Speaker Mode)), PATH_NAME(AMic2(Speaker Mode))}, |
| {HWDEV_DUAL_DMIC1, 0, PATH_NAME(FromDualDMic1), PATH_NAME(DualDMic1)}, |
| {HWDEV_DMIC1, 0, PATH_NAME(FromDMic1), PATH_NAME(DMic1)}, |
| {HWDEV_DMIC2, 0, PATH_NAME(FromDMic2), PATH_NAME(DMic2)}, |
| {HWDEV_HSMIC, 0, PATH_NAME(FromHsMic), PATH_NAME(HsMic)}, |
| {HWDEV_BTMIC_NB, 0, PATH_NAME(FromBTMicNB), NULL}, |
| {HWDEV_BTMIC_NREC_OFF_NB, 0, PATH_NAME(FromBTMicNB(NREC Mode)), NULL}, |
| {HWDEV_BTMIC_WB, 0, PATH_NAME(FromBTMicWB), NULL}, |
| {HWDEV_BTMIC_NREC_OFF_WB, 0, PATH_NAME(FromBTMicWB(NREC Mode)), NULL}, |
| {HWDEV_DUAL_AMIC, 0, PATH_NAME(FromDualAMic), PATH_NAME(DualAMic)}, |
| {HWDEV_DUAL_AMIC_SPK_MODE, 0, PATH_NAME(FromDualAMic(Speaker Mode)),PATH_NAME(DualAMic(Speaker Mode))}, |
| {HWDEV_IN_TTY, 0, PATH_NAME(FromHsMic), PATH_NAME(HsMic)}, |
| {HWDEV_IN_TTY_VCO_AMIC1, 0, PATH_NAME(FromAMic1), PATH_NAME(AMic1)}, |
| {HWDEV_IN_TTY_VCO_AMIC2, 0, PATH_NAME(FromAMic2), PATH_NAME(AMic2)}, |
| {HWDEV_IN_TTY_VCO_DUAL_AMIC, 0, PATH_NAME(FromDualAMic), PATH_NAME(DualAMic)}, |
| {HWDEV_IN_TTY_VCO_DUAL_AMIC_SPK_MODE, 0, PATH_NAME(FromDualAMic(Speaker Mode)), PATH_NAME(DualAMic(Speaker Mode))}, |
| {HWDEV_IN_TTY_VCO_DUAL_DMIC1, 0, PATH_NAME(FromDualDMic1), PATH_NAME(DualDMic1)}, |
| #else |
| // output devices |
| {HWDEV_EARPIECE, 0, '\0', PATH_NAME(VoicePlayToEarphone)}, |
| {HWDEV_SPEAKER, 0, '\0', PATH_NAME(VoicePlayToSPKR)}, |
| {HWDEV_STEREOSPEAKER, 0, '\0', PATH_NAME(VoicePlayToStereoSPKR)}, |
| {HWDEV_HEADPHONE, 0, '\0', PATH_NAME(VoicePlayToHP)}, |
| {HWDEV_BLUETOOTH_NB, 0, '\0', NULL}, |
| {HWDEV_BT_NREC_OFF_NB, 0, '\0', NULL}, |
| {HWDEV_BLUETOOTH_WB, 0, '\0', NULL}, |
| {HWDEV_BT_NREC_OFF_WB, 0, '\0', NULL}, |
| {HWDEV_OUT_TTY, 0, '\0', PATH_NAME(VoicePlayToTty)}, |
| {HWDEV_OUT_TTY_HCO_SPEAKER, 0, '\0', PATH_NAME(VoicePlayToTtyHcoSPKR)}, |
| {HWDEV_OUT_TTY_HCO_STEREOSPEAKER, 0, '\0', PATH_NAME(VoicePlayToTtyHcoStereoSPKR)}, |
| |
| // input devices |
| {HWDEV_AMIC1, 0, '\0', PATH_NAME(VoiceRecordFromMic1)}, |
| {HWDEV_AMIC1_SPK_MODE, 0, '\0', PATH_NAME(Mic1(Speaker Mode))}, //need to modify |
| {HWDEV_AMIC2, 0, '\0', PATH_NAME(Mic2)},//need to modify |
| {HWDEV_AMIC2_SPK_MODE, 0, '\0', PATH_NAME(Mic2(Speaker Mode))},//need to modify |
| {HWDEV_DUAL_DMIC1, 0, '\0', PATH_NAME(DualDMic1)},//need to modify |
| {HWDEV_DMIC1, 0, '\0', PATH_NAME(DMic1)},//need to modify |
| {HWDEV_DMIC2, 0, '\0', PATH_NAME(DMic1)},//need to modify |
| {HWDEV_HSMIC, 0, '\0', PATH_NAME(VoiceRecordFromHsMic)}, |
| {HWDEV_BTMIC_NB, 0, '\0', NULL}, |
| {HWDEV_BTMIC_NREC_OFF_NB, 0, '\0', NULL}, |
| {HWDEV_BTMIC_WB, 0, '\0', NULL}, |
| {HWDEV_BTMIC_NREC_OFF_WB, 0, '\0', NULL}, |
| {HWDEV_DUAL_AMIC, 0, '\0', PATH_NAME(DualAMic)},//need to modify |
| {HWDEV_DUAL_AMIC_SPK_MODE, 0, '\0', PATH_NAME(DualAMic(Speaker Mode))},//need to modify |
| {HWDEV_IN_TTY, 0, '\0', PATH_NAME(VoiceRecordFromTty)}, |
| {HWDEV_IN_TTY_VCO_AMIC1, 0, '\0', PATH_NAME(VoiceRecordFromTtyVcoMic1)}, |
| {HWDEV_IN_TTY_VCO_AMIC2, 0, '\0', PATH_NAME(VoiceRecordFromTtyVcoMic2)}, |
| {HWDEV_IN_TTY_VCO_DUAL_AMIC, 0, '\0', PATH_NAME(VoiceRecordFromTtyVcoDualMic)}, |
| // {HWDEV_IN_TTY_VCO_DUAL_AMIC_SPK_MODE, 0, '\0', PATH_NAME(DualAMic(Speaker Mode))},//need to modify |
| // {HWDEV_IN_TTY_VCO_DUAL_DMIC1, 0, '\0', PATH_NAME(DualDMic1)},//need to modify |
| #endif |
| }; |
| |
| #ifdef PXA1826_AUDIO ////Enable virtual path |
| // define virtual path |
| #define MAX_NUM_VRTL (sizeof(gPathVirtual)/sizeof(gPathVirtual[0])) |
| static const struct |
| { |
| virtual_mode_t v_mode; |
| unsigned int device; |
| unsigned int flag; |
| char* path_name; |
| }gPathVirtual[] = |
| { |
| // HiFi Playback |
| {V_MODE_HIFI_LL, HWDEV_EARPIECE, 0, PATH_NAME(HiFiPlayToEarphone)}, |
| {V_MODE_HIFI_LL, HWDEV_SPEAKER, 0, PATH_NAME(HiFiPlayToSPKR)}, |
| {V_MODE_HIFI_LL, HWDEV_HEADPHONE, 0, PATH_NAME(HiFiPlayToHP)}, |
| |
| // HiFi Record |
| {V_MODE_HIFI_LL, HWDEV_AMIC1, 0, PATH_NAME(HiFiRecordFromMic1)}, |
| {V_MODE_HIFI_LL, HWDEV_AMIC2, 0, PATH_NAME(HiFiRecordFromMic2)}, |
| {V_MODE_HIFI_LL, HWDEV_HSMIC, 0, PATH_NAME(HiFiRecordFromHsMic)}, |
| |
| // Voice Call Playback |
| {V_MODE_VC, HWDEV_EARPIECE, 0, PATH_NAME(VoicePlayToEarphone)}, |
| {V_MODE_VC, HWDEV_SPEAKER, 0, PATH_NAME(VoicePlayToSPKR)}, |
| {V_MODE_VC, HWDEV_HEADPHONE, 0, PATH_NAME(VoicePlayToHP)}, |
| |
| // Voice Call Record |
| {V_MODE_VC, HWDEV_AMIC1, 0, PATH_NAME(VoiceRecordFromMic1)}, |
| {V_MODE_VC, HWDEV_AMIC2, 0, PATH_NAME(VoiceRecordFromMic2)}, |
| {V_MODE_VC, HWDEV_HSMIC, 0, PATH_NAME(VoiceRecordFromHsMic)}, |
| }; |
| #endif |
| |
| static void handle_ctl_info(char *path_name, int method, char *old_path_name, int val) |
| { |
| ACM_ReturnCode ret = ACM_RC_OK; |
| |
| if (path_name == NULL) { |
| ALOGI(handle_ctl_info, "%s NULL path, return directly", __FUNCTION__); |
| return; |
| } |
| |
| switch(method){ |
| case METHOD_ENABLE: |
| ALOGI(handle_ctl_info1, "Enable path %s, value is 0x%lx", path_name, val); |
| ret = ACMAudioPathEnable(path_name, val); |
| break; |
| case METHOD_DISABLE: |
| ALOGI(handle_ctl_info2, "Disable path %s, value is 0x%lx", path_name, val); |
| #ifdef PXA1826_AUDIO |
| ret = ACMAudioPathDisable(path_name); |
| #else |
| ret = ACMAudioPathHotDisable(path_name, val); |
| #endif |
| break; |
| case METHOD_MUTE: |
| ALOGI(handle_ctl_info3, "Mute path %s, value is 0x%lx", path_name, val); |
| ret = ACMAudioPathMute(path_name, val); |
| break; |
| case METHOD_VOLUME_SET: |
| ALOGI(handle_ctl_info4, "Set Volume for path %s, value = 0x%lx", path_name, val); |
| ret = ACMAudioPathVolumeSet(path_name, val); |
| break; |
| case METHOD_SWITCH: |
| { |
| ALOGI(handle_ctl_info5, "Switch from old path %s to path %s, value is 0x%lx", old_path_name, path_name, val); |
| |
| if ((0 == strcmp(path_name, "HiFiPlayToEarphone")) || (0 == strcmp(path_name, "HiFiPlayToSPKR"))) |
| { |
| const char * path_Tx = "HiFiRecordFromMic1"; |
| ret = ACMAudioPathSwitch(path_name, path_Tx, val); |
| } |
| else if (0 == strcmp(path_name, "HiFiPlayToHP")) |
| { |
| const char * path_Tx = "HiFiRecordFromHsMic"; |
| ret = ACMAudioPathSwitch(path_name, path_Tx, val); |
| } |
| else if ((0 == strcmp(path_name, "VoicePlayToEarphone")) || (0 == strcmp(path_name, "VoicePlayToSPKR"))) |
| { |
| const char * path_Tx = "VoiceRecordFromMic1"; |
| ret = ACMAudioPathSwitch(path_name, path_Tx, val); |
| } |
| else if (0 == strcmp(path_name, "VoicePlayToHP")) |
| { |
| const char * path_Tx = "VoiceRecordFromHsMic"; |
| ret = ACMAudioPathSwitch(path_name, path_Tx, val); |
| } |
| else |
| { |
| ret = ACM_RC_OK; |
| } |
| } |
| break; |
| default: |
| ALOGI(handle_ctl_info6, "not support method %d\n", method); |
| break; |
| } |
| if (ret != ACM_RC_OK) { |
| ALOGW(handle_ctl_info7, "%s: Audio path handling error, method: %d error code: %d", __FUNCTION__, method, ret); |
| } |
| } |
| |
| #ifdef PXA1826_AUDIO ////Enable virtual path |
| char *get_vrtl_path(virtual_mode_t v_mode, unsigned int hw_dev, unsigned int flag) |
| { |
| int i = 0; |
| |
| // find ACM path and enable/disable it through ACM |
| for (i = 0; i < (int)MAX_NUM_VRTL; i++) { |
| if ((gPathVirtual[i].v_mode == v_mode) && |
| (gPathVirtual[i].device == hw_dev) && |
| (gPathVirtual[i].flag == flag)) { |
| ALOGD(get_vrtl_path, "%s find path %s", __FUNCTION__, gPathVirtual[i].path_name); |
| return gPathVirtual[i].path_name; |
| } |
| } |
| |
| return NULL; |
| } |
| #else |
| char *get_device_path(unsigned int hw_dev, unsigned int flag) |
| { |
| int i = 0; |
| |
| for (i = 0; i < (int)MAX_NUM_DEV; i++) { |
| if ((gPathDevice[i].device == hw_dev) && |
| (gPathDevice[i].flag == flag)) { |
| ALOGD(get_device_path, "%s find path %s", __FUNCTION__, gPathDevice[i].codec_path); |
| return gPathDevice[i].codec_path; |
| } |
| } |
| |
| return NULL; |
| } |
| #endif |
| |
| #ifdef PXA1826_AUDIO ////Enable virtual path |
| // parameter "flag" is used to search virtual path in audio HAL |
| // parameter "value" is used for register value setting in ACM |
| void route_vrtl_path(virtual_mode_t v_mode, int hw_dev, int enable, unsigned int flag, |
| unsigned int value) |
| { |
| char * path = NULL; |
| ALOGI(route_vrtl_path, "%s mode %d hw_dev 0x%x %s, flag: %d", __FUNCTION__, |
| v_mode, hw_dev, (enable==METHOD_ENABLE)?"enable":"disable", flag); |
| |
| path = get_vrtl_path(v_mode, hw_dev, flag); |
| if (path != NULL) { |
| // set hardware volume to 0 as default. |
| // for normal Hifi/Voice call path, gain still use fix value |
| // for force speaker/FM, we set path mute first, set_volume will set correct volume |
| handle_ctl_info(path, enable, NULL, value); |
| } |
| } |
| #endif |
| void route_hw_device(unsigned int hw_dev, int enable, unsigned int value) |
| { |
| int i = 0; |
| ALOGI(route_hw_device, "%s hw_dev 0x%x %s", __FUNCTION__, |
| hw_dev, (enable==METHOD_ENABLE)?"enable":"disable"); |
| |
| // find ACM path and enable/disable it through ACM |
| for (i = 0; i < (int)MAX_NUM_DEV; i++) { |
| if ((gPathDevice[i].device == hw_dev) && |
| ((gPathDevice[i].flag & value) == gPathDevice[i].flag)) { |
| #ifdef PXA1826_AUDIO //Tzahi S.: don't use APU in pxa1826 |
| ALOGD(route_hw_device1, "%s find path %s", __FUNCTION__, gPathDevice[i].codec_path); |
| #else |
| ALOGD(route_hw_device2, "%s find path %s and %s", __FUNCTION__, |
| gPathDevice[i].apu_path, gPathDevice[i].codec_path); |
| |
| handle_ctl_info(gPathDevice[i].apu_path, enable, NULL, value); |
| handle_ctl_info(gPathDevice[i].codec_path, enable, NULL, value); |
| #endif |
| } |
| } |
| } |
| |
| #ifdef PXA1826_AUDIO ////Enable virtual path |
| // setting hardware volume accroding to virtual mode and hw device |
| void set_hw_volume(virtual_mode_t v_mode, int hw_dev, unsigned int value) |
| { |
| char * path = NULL; |
| path = get_vrtl_path(v_mode, hw_dev, 0); |
| |
| if (path != NULL) { |
| ALOGI(set_hw_volume, "%s path %s volume set to 0x%x\n", __FUNCTION__, path, value); |
| handle_ctl_info(path, METHOD_VOLUME_SET, NULL, value); |
| } |
| } |
| #else //Don't use V_mode in pxa1826_audio |
| // setting hardware volume accroding to hw device |
| void set_hw_volume_by_device(int hw_dev, unsigned int value) |
| { |
| char * path = NULL; |
| path = get_device_path(hw_dev, 0); |
| |
| if (path != NULL) { |
| ALOGI(set_hw_volume_by_device, "%s path %s volume set to 0x%x\n", __FUNCTION__, path, value); |
| handle_ctl_info(path, METHOD_VOLUME_SET, NULL, value); |
| } |
| } |
| #endif |
| |
| // get MSA gain from ACM NVM according to special device |
| void get_msa_gain(unsigned int out_hw_dev, unsigned int hw_dev, 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; |
| unsigned int size = sizeof(ACM_MsaGain); |
| |
| memset(&msa_gain, 0x00, sizeof(ACM_MsaGain)); |
| msa_gain.volume = volume; |
| msa_gain.gain = 0; |
| msa_gain.wbGain = 0; |
| msa_gain.path_direction = 0; |
| |
| #ifdef PXA1826_AUDIO ////Enable virtual path |
| // fix to VC mode here. only VC have msa gain |
| msa_gain.out_path_name = (const unsigned char *)get_vrtl_path(V_MODE_VC, out_hw_dev, 0); |
| msa_gain.path_name = (const unsigned char *)get_vrtl_path(V_MODE_VC, hw_dev, 0); |
| #else |
| msa_gain.out_path_name = (const unsigned char *)get_device_path(out_hw_dev, 0); |
| msa_gain.path_name = (const unsigned char *)get_device_path(hw_dev, 0); |
| #endif |
| |
| if (ACMSetParameter(ACM_MSA_GAIN_MODE, NULL, extra_volume) != ACM_RC_OK) { |
| ALOGI(get_msa_gain, "set output msa gain mode failed, use the default normal mode "); |
| } |
| |
| if (ACMGetParameter(ACM_MSA_GAIN, &msa_gain, &size) != ACM_RC_OK) { |
| ALOGE(get_msa_gain1, "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_gain; |
| } |