/* arch/arm/mach-msm/board-mahimahi-audio.c * * Copyright (C) 2009 HTC Corporation * Copyright (C) 2009 Google Inc. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and * may be copied, distributed, and modified under those terms. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ #include #include #include #include #include #include "board-mahimahi.h" #include "pmic.h" #include "board-mahimahi-tpa2018d1.h" #if 0 #define D(fmt, args...) printk(KERN_INFO "Audio: "fmt, ##args) #else #define D(fmt, args...) do {} while (0) #endif static struct mutex mic_lock; static struct mutex bt_sco_lock; static struct q6_hw_info q6_audio_hw[Q6_HW_COUNT] = { [Q6_HW_HANDSET] = { .min_gain = -2000, .max_gain = 0, }, [Q6_HW_HEADSET] = { .min_gain = -2000, .max_gain = 0, }, [Q6_HW_SPEAKER] = { .min_gain = -1500, .max_gain = 0, }, [Q6_HW_TTY] = { .min_gain = -2000, .max_gain = 0, }, [Q6_HW_BT_SCO] = { .min_gain = -2000, .max_gain = 0, }, [Q6_HW_BT_A2DP] = { .min_gain = -2000, .max_gain = 0, }, }; void mahimahi_headset_enable(int en) { D("%s %d\n", __func__, en); /* enable audio amp */ if (en) mdelay(15); gpio_set_value(MAHIMAHI_AUD_JACKHP_EN, !!en); } void mahimahi_speaker_enable(int en) { struct spkr_config_mode scm; memset(&scm, 0, sizeof(scm)); D("%s %d\n", __func__, en); if (en) { scm.is_right_chan_en = 0; scm.is_left_chan_en = 1; scm.is_stereo_en = 0; scm.is_hpf_en = 1; pmic_spkr_en_mute(LEFT_SPKR, 0); pmic_spkr_en_mute(RIGHT_SPKR, 0); pmic_set_spkr_configuration(&scm); pmic_spkr_en(LEFT_SPKR, 1); pmic_spkr_en(RIGHT_SPKR, 0); /* unmute */ pmic_spkr_en_mute(LEFT_SPKR, 1); } else { pmic_spkr_en_mute(LEFT_SPKR, 0); pmic_spkr_en(LEFT_SPKR, 0); pmic_spkr_en(RIGHT_SPKR, 0); pmic_set_spkr_configuration(&scm); } if (is_cdma_version(system_rev)) tpa2018d1_set_speaker_amp(en); } void mahimahi_receiver_enable(int en) { if (is_cdma_version(system_rev) && ((system_rev == 0xC1) || (system_rev == 0xC2))) { struct spkr_config_mode scm; memset(&scm, 0, sizeof(scm)); D("%s %d\n", __func__, en); if (en) { scm.is_right_chan_en = 1; scm.is_left_chan_en = 0; scm.is_stereo_en = 0; scm.is_hpf_en = 1; pmic_spkr_en_mute(RIGHT_SPKR, 0); pmic_set_spkr_configuration(&scm); pmic_spkr_en(RIGHT_SPKR, 1); /* unmute */ pmic_spkr_en_mute(RIGHT_SPKR, 1); } else { pmic_spkr_en_mute(RIGHT_SPKR, 0); pmic_spkr_en(RIGHT_SPKR, 0); pmic_set_spkr_configuration(&scm); } } } static void config_gpio_table(uint32_t *table, int len) { int n; unsigned id; for (n = 0; n < len; n++) { id = table[n]; msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0); } } static uint32_t bt_sco_enable[] = { PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_OUT, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_IN, 1, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_SYNC, 2, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_CLK, 2, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), }; static uint32_t bt_sco_disable[] = { PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_OUT, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_IN, 0, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_SYNC, 0, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_CLK, 0, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), }; void mahimahi_bt_sco_enable(int en) { static int bt_sco_refcount; D("%s %d\n", __func__, en); mutex_lock(&bt_sco_lock); if (en) { if (++bt_sco_refcount == 1) config_gpio_table(bt_sco_enable, ARRAY_SIZE(bt_sco_enable)); } else { if (--bt_sco_refcount == 0) { config_gpio_table(bt_sco_disable, ARRAY_SIZE(bt_sco_disable)); gpio_set_value(MAHIMAHI_BT_PCM_OUT, 0); } } mutex_unlock(&bt_sco_lock); } void mahimahi_mic_enable(int en) { static int old_state = 0, new_state = 0; D("%s %d\n", __func__, en); mutex_lock(&mic_lock); if (!!en) new_state++; else new_state--; if (new_state == 1 && old_state == 0) { gpio_set_value(MAHIMAHI_AUD_2V5_EN, 1); mdelay(60); } else if (new_state == 0 && old_state == 1) gpio_set_value(MAHIMAHI_AUD_2V5_EN, 0); else D("%s: do nothing %d %d\n", __func__, old_state, new_state); old_state = new_state; mutex_unlock(&mic_lock); } void mahimahi_analog_init(void) { D("%s\n", __func__); /* stereo pmic init */ pmic_spkr_set_gain(LEFT_SPKR, SPKR_GAIN_PLUS12DB); pmic_spkr_set_gain(RIGHT_SPKR, SPKR_GAIN_PLUS12DB); pmic_spkr_en_right_chan(OFF_CMD); pmic_spkr_en_left_chan(OFF_CMD); pmic_spkr_add_right_left_chan(OFF_CMD); pmic_spkr_en_stereo(OFF_CMD); pmic_spkr_select_usb_with_hpf_20hz(OFF_CMD); pmic_spkr_bypass_mux(OFF_CMD); pmic_spkr_en_hpf(ON_CMD); pmic_spkr_en_sink_curr_from_ref_volt_cir(OFF_CMD); pmic_spkr_set_mux_hpf_corner_freq(SPKR_FREQ_0_73KHZ); pmic_mic_set_volt(MIC_VOLT_1_80V); gpio_request(MAHIMAHI_AUD_JACKHP_EN, "aud_jackhp_en"); gpio_request(MAHIMAHI_BT_PCM_OUT, "bt_pcm_out"); gpio_direction_output(MAHIMAHI_AUD_JACKHP_EN, 0); mutex_lock(&bt_sco_lock); config_gpio_table(bt_sco_disable, ARRAY_SIZE(bt_sco_disable)); gpio_direction_output(MAHIMAHI_BT_PCM_OUT, 0); mutex_unlock(&bt_sco_lock); } int mahimahi_get_rx_vol(uint8_t hw, int level) { int vol; if (level > 100) level = 100; else if (level < 0) level = 0; if (is_cdma_version(system_rev) && hw == Q6_HW_HANDSET) { int handset_volume[6] = { -1600, -1300, -1000, -600, -300, 0 }; vol = handset_volume[5 * level / 100]; } else { struct q6_hw_info *info; info = &q6_audio_hw[hw]; vol = info->min_gain + ((info->max_gain - info->min_gain) * level) / 100; } D("%s %d\n", __func__, vol); return vol; } static struct qsd_acoustic_ops acoustic = { .enable_mic_bias = mahimahi_mic_enable, }; static struct q6audio_analog_ops ops = { .init = mahimahi_analog_init, .speaker_enable = mahimahi_speaker_enable, .headset_enable = mahimahi_headset_enable, .receiver_enable = mahimahi_receiver_enable, .bt_sco_enable = mahimahi_bt_sco_enable, .int_mic_enable = mahimahi_mic_enable, .ext_mic_enable = mahimahi_mic_enable, .get_rx_vol = mahimahi_get_rx_vol, }; void __init mahimahi_audio_init(void) { mutex_init(&mic_lock); mutex_init(&bt_sco_lock); q6audio_register_analog_ops(&ops); acoustic_register_ops(&acoustic); if (is_cdma_version(system_rev) && ((system_rev == 0xC1) || (system_rev == 0xC2))) q6audio_set_acdb_file("default_PMIC.acdb"); }