/* arch/arm/mach-msm/board-htcleo-audio.c * * Copyright (C) 2010 Cotulla * * 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 #include "board-htcleo.h" #include "devices.h" #include "dex_comm.h" #include "proc_comm.h" #include "pmic.h" #if 1 #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; #if 1 // LEO 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 = -1000, .max_gain = 500, }, [Q6_HW_TTY] = { .min_gain = 0, .max_gain = 0, }, [Q6_HW_BT_SCO] = { .min_gain = -1100, .max_gain = 400, }, [Q6_HW_BT_A2DP] = { .min_gain = -1100, .max_gain = 400, }, }; #else // old desire one 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, }, }; #endif void htcleo_headset_enable(int en) { D("%s %d\n", __func__, en); /* enable audio amp */ if (en) mdelay(60); gpio_set_value(HTCLEO_AUD_JACKHP_EN, !!en); } void htcleo_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 = 0; //1; // CotullaTODO: check it pmic_spkr_en_mute(LEFT_SPKR, 0); pmic_spkr_en_mute(RIGHT_SPKR, 0); pmic_set_spkr_configuration(&scm); pmic_spkr_set_mux_hpf_corner_freq(SPKR_FREQ_0_76KHZ); pmic_spkr_en(LEFT_SPKR, 1); pmic_spkr_en(RIGHT_SPKR, 0); pmic_spkr_en_hpf(ON_CMD); // +LEO /* unmute */ pmic_spkr_en_mute(LEFT_SPKR, 1); mdelay(40); } else { pmic_spkr_en_mute(LEFT_SPKR, 0); pmic_spkr_en_hpf(OFF_CMD); // +LEO pmic_spkr_en(LEFT_SPKR, 0); pmic_spkr_en(RIGHT_SPKR, 0); pmic_set_spkr_configuration(&scm); } } void htcleo_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 uint32_t bt_sco_enable[] = { PCOM_GPIO_CFG(HTCLEO_BT_PCM_OUT, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), PCOM_GPIO_CFG(HTCLEO_BT_PCM_IN, 1, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), PCOM_GPIO_CFG(HTCLEO_BT_PCM_SYNC, 2, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), PCOM_GPIO_CFG(HTCLEO_BT_PCM_CLK, 2, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA) }; static uint32_t bt_sco_disable[] = { PCOM_GPIO_CFG(HTCLEO_BT_PCM_OUT, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), PCOM_GPIO_CFG(HTCLEO_BT_PCM_IN, 0, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), PCOM_GPIO_CFG(HTCLEO_BT_PCM_SYNC, 0, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), PCOM_GPIO_CFG(HTCLEO_BT_PCM_CLK, 0, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA) }; void htcleo_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(HTCLEO_BT_PCM_OUT, 0); } } mutex_unlock(&bt_sco_lock); } void htcleo_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(HTCLEO_AUD_2V5_EN, 1); mdelay(60); } else if (new_state == 0 && old_state == 1) { gpio_set_value(HTCLEO_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 htcleo_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(OFF_CMD); pmic_spkr_en_sink_curr_from_ref_volt_cir(OFF_CMD); pmic_spkr_set_mux_hpf_corner_freq(SPKR_FREQ_0_76KHZ); pmic_mic_set_volt(MIC_VOLT_1_80V); gpio_request(HTCLEO_AUD_JACKHP_EN, "aud_jackhp_en"); gpio_request(HTCLEO_BT_PCM_OUT, "bt_pcm_out"); gpio_direction_output(HTCLEO_AUD_JACKHP_EN, 0); mutex_lock(&bt_sco_lock); config_gpio_table(bt_sco_disable, ARRAY_SIZE(bt_sco_disable)); gpio_direction_output(HTCLEO_BT_PCM_OUT, 0); mutex_unlock(&bt_sco_lock); } int htcleo_get_rx_vol(uint8_t hw, int level) { int vol; if (level > 100) level = 100; else if (level < 0) level = 0; // TODO: is it correct? 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 = htcleo_mic_enable, }; static struct q6audio_analog_ops ops = { .init = htcleo_analog_init, .speaker_enable = htcleo_speaker_enable, .headset_enable = htcleo_headset_enable, .receiver_enable = htcleo_receiver_enable, .bt_sco_enable = htcleo_bt_sco_enable, .int_mic_enable = htcleo_mic_enable, .ext_mic_enable = htcleo_mic_enable, .get_rx_vol = htcleo_get_rx_vol, }; void __init htcleo_audio_init(void) { mutex_init(&mic_lock); mutex_init(&bt_sco_lock); q6audio_register_analog_ops(&ops); acoustic_register_ops(&acoustic); // q6audio_set_acdb_file("default_PMIC.acdb"); } // END OF FILE