diff options
Diffstat (limited to 'sound/soc/msm/msm8996.c')
-rw-r--r-- | sound/soc/msm/msm8996.c | 227 |
1 files changed, 221 insertions, 6 deletions
diff --git a/sound/soc/msm/msm8996.c b/sound/soc/msm/msm8996.c index 47cd28af1b84..63ab59b89197 100644 --- a/sound/soc/msm/msm8996.c +++ b/sound/soc/msm/msm8996.c @@ -63,6 +63,24 @@ #define WSA8810_NAME_1 "wsa881x.20170211" #define WSA8810_NAME_2 "wsa881x.20170212" +#define NCX_VTG_MIN_UV 3000000 +#define NCX_VTG_MAX_UV 3000000 +#ifdef CONFIG_MACH_ZUK_Z2_ROW +#define QUAT_MI2S_ENABLE +#endif +#ifdef QUAT_MI2S_ENABLE +atomic_t quat_mi2s_rsc_ref; +atomic_t quat_mi2s_clk_ref; +static bool system_bootup = 1; +static struct afe_clk_set mi2s_rx_clk = { + AFE_API_VERSION_I2S_CONFIG, + Q6AFE_LPASS_CLK_ID_QUAD_MI2S_IBIT, + Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ, + Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO, + Q6AFE_LPASS_CLK_ROOT_DEFAULT, + 0, +}; +#endif static int slim0_rx_sample_rate = SAMPLING_RATE_48KHZ; static int slim0_tx_sample_rate = SAMPLING_RATE_48KHZ; @@ -335,6 +353,9 @@ static int msm_hdmi_rx_ch = 2; static int msm_proxy_rx_ch = 2; static int hdmi_rx_sample_rate = SAMPLING_RATE_48KHZ; static int msm_tert_mi2s_tx_ch = 2; +#ifdef QUAT_MI2S_ENABLE +static int msm_quat_mi2s_ch = 2; +#endif static bool codec_reg_done; @@ -474,10 +495,10 @@ static struct wcd_mbhc_config wcd_mbhc_cfg = { .mono_stero_detection = false, .swap_gnd_mic = NULL, .hs_ext_micbias = true, - .key_code[0] = KEY_MEDIA, - .key_code[1] = KEY_VOICECOMMAND, - .key_code[2] = KEY_VOLUMEUP, - .key_code[3] = KEY_VOLUMEDOWN, + .key_code[0] = BTN_0, + .key_code[1] = BTN_1, + .key_code[2] = BTN_2, + .key_code[3] = BTN_3, .key_code[4] = 0, .key_code[5] = 0, .key_code[6] = 0, @@ -489,6 +510,38 @@ static struct wcd_mbhc_config wcd_mbhc_cfg = { .enable_anc_mic_detect = false, }; +#define HEADSET_TYPE_STANDARD +#ifdef HEADSET_TYPE_STANDARD +static int gnd_mic_gpio_state = -1; +static int headset_standard_get = 0; +static int headset_type_standard = -1; // 0 America, 1 Europe standard +static int headset_standard_get_parm_set(const char *val, struct kernel_param *kp) +{ + param_set_int(val, kp); + if (1 == headset_standard_get) { + if (-1 == gnd_mic_gpio_state) + headset_type_standard = 0; + else + headset_type_standard = gnd_mic_gpio_state; + printk(KERN_INFO "%s enter, headset_type_standard = %d\n", + __func__, headset_type_standard); + } else { + printk(KERN_INFO "enter %s, clear the headset/headphone type\n", __func__); + headset_type_standard = -1; + } + return 0; +} +module_param_call(headset_standard_get, headset_standard_get_parm_set, param_get_int, + &headset_standard_get, 0644); +static int headset_type_standard_parm_set(const char *val, struct kernel_param *kp) +{ + param_set_int(val, kp); + return 0; +} +module_param_call(headset_type_standard, headset_type_standard_parm_set, param_get_int, + &headset_type_standard, 0644); +#endif + static inline int param_is_mask(int p) { return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) && @@ -4341,6 +4394,66 @@ static int msm_slim_5_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, return rc; } +#ifdef QUAT_MI2S_ENABLE +static int msm8996_quat_mi2s_startup(struct snd_pcm_substream *substream) +{ + int ret = 0; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + pr_info("%s: dai name %s %p\n", __func__, cpu_dai->name, cpu_dai->dev); + if (atomic_inc_return(&quat_mi2s_rsc_ref) == 1) { + pr_info("%s: acquire mi2s resources\n", __func__); + if (atomic_inc_return(&quat_mi2s_clk_ref) == 1) { + mi2s_rx_clk.enable = 1; + ret = afe_set_lpass_clock_v2(AFE_PORT_ID_QUATERNARY_MI2S_RX, &mi2s_rx_clk); + if (ret < 0) { + pr_err("%s: afe_set_lpass_clock failed\n", __func__); + return ret; + } + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + dev_err(cpu_dai->dev, "set format for CPU dai" + " failed\n"); + } + } + return ret; +} +static void msm8996_quat_mi2s_shutdown(struct snd_pcm_substream *substream) +{ + int ret = 0; + pr_debug("%s: substream = %s stream = %d\n", __func__, + substream->name, substream->stream); + if (atomic_dec_return(&quat_mi2s_rsc_ref) == 0) { + if (atomic_dec_return(&quat_mi2s_clk_ref) == 0) { + mi2s_rx_clk.enable = 0; + ret = afe_set_lpass_clock_v2(AFE_PORT_ID_QUATERNARY_MI2S_RX, + &mi2s_rx_clk); + if (ret < 0) + pr_err("%s: afe lpass clock failed, err:%d\n", __func__, ret); + } + } +} +static struct snd_soc_ops msm8996_quat_mi2s_be_ops = { + .startup = msm8996_quat_mi2s_startup, + .shutdown = msm8996_quat_mi2s_shutdown +}; + +static int msm_be_quat_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + pr_debug("%s: channel:%d\n", __func__, msm_quat_mi2s_ch); + rate->min = rate->max = SAMPLING_RATE_48KHZ; + channels->min = channels->max = msm_quat_mi2s_ch; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + SNDRV_PCM_FORMAT_S16_LE); + return 0; +} +#endif + static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { @@ -5593,6 +5706,20 @@ static bool msm8996_swap_gnd_mic(struct snd_soc_codec *codec) pr_debug("%s: swap select switch %d to %d\n", __func__, value, !value); gpio_set_value_cansleep(pdata->us_euro_gpio, !value); + gnd_mic_gpio_state = !value; + return true; +} + +static bool msm8996_default_gnd_mic(struct snd_soc_codec *codec) +{ + struct snd_soc_card *card = codec->component.card; + struct msm8996_asoc_mach_data *pdata = + snd_soc_card_get_drvdata(card); + int value = 0; + + pr_debug("%s: set select switch to default value %d\n", __func__, value); + gpio_set_value_cansleep(pdata->us_euro_gpio, value); + gnd_mic_gpio_state = 0; return true; } @@ -6910,6 +7037,23 @@ static struct snd_soc_dai_link msm8996_common_dai_links[] = { .codec_name = "snd-soc-dummy", .be_id = MSM_FRONTEND_DAI_VOICE2, }, +#ifdef QUAT_MI2S_ENABLE + { + .name = "MI2S_TX Hostless", + .stream_name = "MI2S_TX Hostless", + .cpu_dai_name = "MI2S_TX_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, +#endif }; static struct snd_soc_dai_link msm8996_tdm_fe_dai_links[] = { { @@ -7635,7 +7779,37 @@ static struct snd_soc_dai_link msm8996_common_be_dai_links[] = { .be_id = MSM_BACKEND_DAI_USB_TX, .be_hw_params_fixup = msm_be_hw_params_fixup, .ignore_suspend = 1, - } + }, +#ifdef QUAT_MI2S_ENABLE + { + .name = LPASS_BE_QUAT_MI2S_RX, + .stream_name = "Quaternary MI2S Playback", + .cpu_dai_name = "msm-dai-q6-mi2s.3", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .be_id = MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + .be_hw_params_fixup = msm_be_quat_hw_params_fixup, + .ops = &msm8996_quat_mi2s_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_QUAT_MI2S_TX, + .stream_name = "Quaternary MI2S Capture", + .cpu_dai_name = "msm-dai-q6-mi2s.3", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .be_id = MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, + .be_hw_params_fixup = msm_be_quat_hw_params_fixup, + .ops = &msm8996_quat_mi2s_be_ops, + .ignore_suspend = 1, + }, +#endif }; static struct snd_soc_dai_link msm8996_tasha_be_dai_links[] = { @@ -8550,7 +8724,9 @@ static int msm8996_init_wsa_dev(struct platform_device *pdev, int found = 0; int i; int ret; - +#ifndef CONFIG_SND_SOC_WSA881X + return -EINVAL; +#endif /* Get maximum WSA device count for this platform */ ret = of_property_read_u32(pdev->dev.of_node, "qcom,wsa-max-devs", &wsa_max_devs); @@ -8781,8 +8957,10 @@ static int msm8996_asoc_machine_probe(struct platform_device *pdev) } ret = msm8996_init_wsa_dev(pdev, card); +#ifdef CONFIG_SND_SOC_WSA881X if (ret) goto err; +#endif pdata->hph_en1_gpio = of_get_named_gpio(pdev->dev.of_node, "qcom,hph-en1-gpio", 0); @@ -8801,6 +8979,13 @@ static int msm8996_asoc_machine_probe(struct platform_device *pdev) if (ret) dev_dbg(&pdev->dev, "msm8996_prepare_hifi failed (%d)\n", ret); +#ifdef QUAT_MI2S_ENABLE + if(system_bootup){ + system_bootup = 0; + atomic_set(&quat_mi2s_rsc_ref, 0); + atomic_set(&quat_mi2s_clk_ref, 0); + } +#endif ret = snd_soc_register_card(card); if (ret == -EPROBE_DEFER) { @@ -8847,13 +9032,43 @@ static int msm8996_asoc_machine_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "%s detected %d", "qcom,us-euro-gpios", pdata->us_euro_gpio); wcd_mbhc_cfg.swap_gnd_mic = msm8996_swap_gnd_mic; + wcd_mbhc_cfg.default_gnd_mic = msm8996_default_gnd_mic; } ret = msm8996_prepare_us_euro(card); if (ret) dev_info(&pdev->dev, "msm8996_prepare_us_euro failed (%d)\n", ret); +#ifdef NCX8200 + /* Enable VDD for NCX8200*/ + wcd_mbhc_cfg.vdd = regulator_get(&pdev->dev, "ncx_vdd"); + dev_info(&pdev->dev, + "Regulator get ncx_vdd ret=%d\n", ret); + if (IS_ERR(wcd_mbhc_cfg.vdd)) { + ret = PTR_ERR(wcd_mbhc_cfg.vdd); + dev_info(&pdev->dev, + "Regulator get failed vdd ret=%d\n", ret); + } else if (regulator_count_voltages(wcd_mbhc_cfg.vdd) > 0) { + ret = regulator_set_voltage(wcd_mbhc_cfg.vdd, NCX_VTG_MIN_UV, NCX_VTG_MAX_UV); + if (ret) { + dev_err(&pdev->dev, + "Regulator set_vtg failed vdd ret=%d\n", ret); + goto err_vdd_put; + } + } + if (!IS_ERR(wcd_mbhc_cfg.vdd)) { + ret = regulator_enable(wcd_mbhc_cfg.vdd); + if (ret) { + dev_err(&pdev->dev, + "Regulator vdd enable failed ret=%d\n", ret); + } + } +#endif return 0; +#ifdef NCX8200 + err_vdd_put: + regulator_put(wcd_mbhc_cfg.vdd); +#endif err: if (pdata->us_euro_gpio > 0) { dev_dbg(&pdev->dev, "%s free us_euro gpio %d\n", |