summaryrefslogtreecommitdiff
path: root/sound/soc/msm/msm8996.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/msm/msm8996.c')
-rw-r--r--sound/soc/msm/msm8996.c227
1 files changed, 221 insertions, 6 deletions
diff --git a/sound/soc/msm/msm8996.c b/sound/soc/msm/msm8996.c
index 47cd28af1b84..cb7bb1f34492 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, const 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, const 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",