blob: d3fee31a9bca6d6503da353394c713e5ed4147bf [file] [log] [blame]
/*
* 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;
}