Loading Documentation/devicetree/bindings/sound/qcom-audio-dev.txt +1 −1 Original line number Diff line number Diff line Loading @@ -1036,7 +1036,7 @@ Optional properties: - pinctrl-states: the names of the pinctrl states that used by the driver to configure the TLMM pins. The allowed states are subset of the following list: pmx-pri-mi2s-active, pmx-pri-quad-mi2s-active, pmx-quad-mi2s-active, pmx-pri-quad-mi2s-sleep. pmx-pri-quad-mi2s-sleep, pmx-quad-mi2s-sleep. - pinctrl-#: a list of pinctrl phandles for the different pinctrl states. Refer to "Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt" for the pinctrl handles definitions. Each pinctrl-# corresponds to the respective Loading sound/soc/msm/apq8084.c +481 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,8 @@ static int slim0_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE; static int hdmi_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE; static int mi2s_tx_bit_format = SNDRV_PCM_FORMAT_S16_LE; static int mi2s_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE; #define SAMPLING_RATE_8KHZ 8000 #define SAMPLING_RATE_16KHZ 16000 Loading Loading @@ -147,11 +149,52 @@ struct msm_auxpcm_ctrl { u32 cnt; }; static const struct afe_clk_cfg lpass_default = { AFE_API_VERSION_I2S_CONFIG, Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ, Q6AFE_LPASS_OSR_CLK_DISABLE, Q6AFE_LPASS_CLK_SRC_INTERNAL, Q6AFE_LPASS_CLK_ROOT_DEFAULT, Q6AFE_LPASS_MODE_CLK1_VALID, 0, }; static const char *const mi2s_pin_states[] = {"Disable", "quad_mi2s_active"}; /* * enum mi2s_pin_state - states for the mi2s pinctrl states * Note: these states are similar to the "pinctrl-names" * in board/target specific DTSI file. */ enum mi2s_pin_state { MI2S_STATE_DISABLE = 0, MI2S_STATE_QUAD_ON = 1 }; /* * struct msm_mi2s_pinctrl_info - manage all the pinctrl information * * @pinctrl: TSC pinctrl state holder. * @disable: pinctrl state to disable all the pins. * @quad_mi2s_active: pinctrl state to activate Quaternary MI2S. * @curr_state: the current state of the TLMM pins. */ struct msm_mi2s_pinctrl_info { struct pinctrl *pinctrl; struct pinctrl_state *disable; struct pinctrl_state *quad_mi2s_active; enum mi2s_pin_state curr_mi2s_state; }; struct apq8084_asoc_mach_data { u32 mclk_freq; int us_euro_gpio; struct msm_auxpcm_ctrl *pri_auxpcm_ctrl; struct msm_auxpcm_ctrl *sec_auxpcm_ctrl; u32 quad_rx_clk_usrs; u32 quad_tx_clk_usrs; struct msm_mi2s_pinctrl_info mi2s_pinctrl_info; }; struct apq8084_asoc_wcd93xx_codec { Loading Loading @@ -185,6 +228,7 @@ static char *msm_sec_auxpcm_gpio_name[][2] = { void *lpaif_pri_muxsel_virt_addr; void *lpaif_sec_muxsel_virt_addr; void *lpaif_quad_muxsel_virt_addr; struct apq8084_liquid_dock_dev { int dock_plug_gpio; Loading Loading @@ -243,6 +287,12 @@ static int clk_users; static atomic_t prim_auxpcm_rsc_ref; static atomic_t sec_auxpcm_rsc_ref; static bool codec_reg_done; static int apq8084_mi2s_rx_ch = 1; static int apq8084_mi2s_tx_ch = 1; static atomic_t quad_mi2s_ref_count; static const char *const mi2s_tx_ch_text[] = {"One", "Two"}; static const char *const mi2s_rx_ch_text[] = {"One", "Two"}; static int apq8084_liquid_ext_spk_power_amp_init(void) { Loading Loading @@ -1289,6 +1339,322 @@ static struct snd_soc_ops msm_sec_auxpcm_be_ops = { .shutdown = msm_sec_auxpcm_shutdown, }; static int msm_quad_mi2s_set_pinctrl(struct apq8084_asoc_mach_data *pdata) { struct msm_mi2s_pinctrl_info *pinctrl_info = &pdata->mi2s_pinctrl_info; int ret = 0; pr_debug("%s: curr_mi2s_state = %s\n", __func__, mi2s_pin_states[pinctrl_info->curr_mi2s_state]); /* Enable Quaternary MI2S TLMM pins and set to appropriate state */ switch (pinctrl_info->curr_mi2s_state) { case MI2S_STATE_DISABLE: ret = pinctrl_select_state(pinctrl_info->pinctrl, pinctrl_info->quad_mi2s_active); if (ret) { pr_err("%s: pinctrl_select_state failed with %d\n", __func__, ret); ret = -EIO; goto err; } pinctrl_info->curr_mi2s_state = MI2S_STATE_QUAD_ON; break; case MI2S_STATE_QUAD_ON: pr_err("%s: MI2S TLMM pins already set\n", __func__); break; default: pr_err("%s: MI2S TLMM pin state is invalid\n", __func__); return -EINVAL; } err: return ret; } static int msm_quad_mi2s_reset_pinctrl(struct apq8084_asoc_mach_data *pdata) { struct msm_mi2s_pinctrl_info *pinctrl_info = &pdata->mi2s_pinctrl_info; int ret = 0; pr_debug("%s: curr_mi2s_state = %s\n", __func__, mi2s_pin_states[pinctrl_info->curr_mi2s_state]); /* Reset Quaternary MI2S TLMM pins and set to appropriate state */ switch (pinctrl_info->curr_mi2s_state) { case MI2S_STATE_QUAD_ON: ret = pinctrl_select_state(pinctrl_info->pinctrl, pinctrl_info->disable); if (ret) { pr_err("%s: pinctrl_select_state failed with %d\n", __func__, ret); ret = -EIO; goto err; } pinctrl_info->curr_mi2s_state = MI2S_STATE_DISABLE; break; case MI2S_STATE_DISABLE: pr_err("%s: MI2S TLMM pins already disabled\n", __func__); break; default: pr_err("%s: MI2S TLMM pin state is invalid\n", __func__); return -EINVAL; } err: return ret; } static int apq8084_quad_mi2s_clk_ctl(struct snd_soc_pcm_runtime *rtd, bool enable, struct snd_pcm_substream *substream) { struct snd_soc_card *card = rtd->card; struct apq8084_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); struct afe_clk_cfg *lpass_clk = NULL; int ret = 0; u32 afe_port_id; if (pdata == NULL) { pr_err("%s:platform data is null\n", __func__); return -EINVAL; } lpass_clk = kzalloc(sizeof(struct afe_clk_cfg), GFP_KERNEL); if (lpass_clk == NULL) { pr_err("%s:Failed to allocate memory\n", __func__); return -ENOMEM; } memcpy(lpass_clk, &lpass_default, sizeof(struct afe_clk_cfg)); pr_debug("%s: lpass clock enable = %d\n", __func__, enable); if (enable) { if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { afe_port_id = AFE_PORT_ID_QUATERNARY_MI2S_RX; if (pdata->quad_rx_clk_usrs == 0) { lpass_clk->clk_val1 = Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ; lpass_clk->clk_set_mode = Q6AFE_LPASS_MODE_CLK1_VALID; } ret = afe_set_lpass_clock(afe_port_id, lpass_clk); if (ret < 0) { pr_err("%s:afe_set_lpass_clock failed with %d\n", __func__, ret); goto err; } else { pdata->quad_rx_clk_usrs++; } } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { afe_port_id = AFE_PORT_ID_QUATERNARY_MI2S_TX; if (pdata->quad_tx_clk_usrs == 0) { lpass_clk->clk_val1 = Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ; lpass_clk->clk_set_mode = Q6AFE_LPASS_MODE_CLK1_VALID; } ret = afe_set_lpass_clock(afe_port_id, lpass_clk); if (ret < 0) { pr_err("%s:afe_set_lpass_clock failed with %d\n", __func__, ret); goto err; } else { pdata->quad_tx_clk_usrs++; } } } else { if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { afe_port_id = AFE_PORT_ID_QUATERNARY_MI2S_RX; if (pdata->quad_rx_clk_usrs > 0) pdata->quad_rx_clk_usrs--; if (pdata->quad_rx_clk_usrs == 0) { lpass_clk->clk_val1 = Q6AFE_LPASS_IBIT_CLK_DISABLE; lpass_clk->clk_set_mode = Q6AFE_LPASS_MODE_CLK1_VALID; } ret = afe_set_lpass_clock(afe_port_id, lpass_clk); if (ret < 0) { pr_err("%s:afe_set_lpass_clock failed with %d\n", __func__, ret); goto err; } } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { afe_port_id = AFE_PORT_ID_QUATERNARY_MI2S_TX; if (pdata->quad_tx_clk_usrs > 0) pdata->quad_tx_clk_usrs--; if (pdata->quad_tx_clk_usrs == 0) { lpass_clk->clk_val1 = Q6AFE_LPASS_IBIT_CLK_DISABLE; lpass_clk->clk_set_mode = Q6AFE_LPASS_MODE_CLK1_VALID; } ret = afe_set_lpass_clock(afe_port_id, lpass_clk); if (ret < 0) { pr_err("%s:afe_set_lpass_clock failed with %d\n", __func__, ret); goto err; } } } pr_debug("%s: clk 1 = 0x%x clk2 = 0x%x mode = 0x%x\n", __func__, lpass_clk->clk_val1, lpass_clk->clk_val2, lpass_clk->clk_set_mode); ret = 0; err: kfree(lpass_clk); return ret; } static int msm_quad_mi2s_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_card *card = rtd->card; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct apq8084_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); int ret = 0; uint32_t pcm_sel_reg; pr_debug("%s(): substream = %s, quad_mi2s_ref_count = %d\n", __func__, substream->name, atomic_read(&quad_mi2s_ref_count)); if (pdata == NULL || lpaif_quad_muxsel_virt_addr == NULL) { pr_err("%s: Invalid parameters for Quad MI2S\n", __func__); ret = -EINVAL; goto err; } if (atomic_inc_return(&quad_mi2s_ref_count) == 1) { pcm_sel_reg = ioread32(lpaif_quad_muxsel_virt_addr); if (pcm_sel_reg & (I2S_PCM_SEL << I2S_PCM_SEL_OFFSET)) { iowrite32(pcm_sel_reg & ~(I2S_PCM_SEL << I2S_PCM_SEL_OFFSET), lpaif_quad_muxsel_virt_addr); } ret = msm_quad_mi2s_set_pinctrl(pdata); if (ret) { pr_err("%s: MI2S TLMM pinctrl set failed with %d\n", __func__, ret); return ret; } ret = apq8084_quad_mi2s_clk_ctl(rtd, true, substream); if (ret) { pr_err("%s: Setting clk control failed with %d\n", __func__, ret); return ret; } /* This sets the CONFIG PARAMETER WS_SRC. * SND_SOC_DAIFMT_CBS_CFS means internal clock/master mode. * SND_SOC_DAIFMT_CBM_CFM means external clock/slave mode. */ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS); if (ret) pr_err("%s: set fmt cpu dai failed with %d\n", __func__, ret); } err: return ret; } static void msm_quad_mi2s_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_card *card = rtd->card; struct apq8084_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); int ret; pr_debug("%s(): substream = %s, quad_mi2s_ref_count = %d\n", __func__, substream->name, atomic_read(&quad_mi2s_ref_count)); if (pdata == NULL) { pr_err("%s: Invalid platform data\n", __func__); return; } if (atomic_dec_return(&quad_mi2s_ref_count) == 0) { ret = msm_quad_mi2s_reset_pinctrl(pdata); if (ret) pr_err("%s Reset pinctrl failed with %d\n", __func__, ret); ret = apq8084_quad_mi2s_clk_ctl(rtd, false, substream); if (ret) pr_err("%s Clock disable failed with %d\n", __func__, ret); } } static struct snd_soc_ops apq8084_quad_mi2s_be_ops = { .startup = msm_quad_mi2s_startup, .shutdown = msm_quad_mi2s_shutdown, }; static int apq8084_mi2s_tx_be_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); param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, mi2s_tx_bit_format); rate->min = rate->max = SAMPLING_RATE_48KHZ; channels->min = channels->max = apq8084_mi2s_tx_ch; pr_debug("%s: format = %d rate = %d, channels = %d\n", __func__, params_format(params), params_rate(params), apq8084_mi2s_tx_ch); return 0; } static int apq8084_mi2s_tx_ch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s: apq8084_i2s_tx_ch = %d\n", __func__, apq8084_mi2s_tx_ch); ucontrol->value.integer.value[0] = apq8084_mi2s_tx_ch - 1; return 0; } static int apq8084_mi2s_tx_ch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { apq8084_mi2s_tx_ch = ucontrol->value.integer.value[0] + 1; pr_debug("%s: apq8084_i2s_tx_ch = %d\n", __func__, apq8084_mi2s_tx_ch); return 1; } static int apq8084_mi2s_rx_be_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); param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, mi2s_rx_bit_format); rate->min = rate->max = SAMPLING_RATE_48KHZ; channels->min = channels->max = apq8084_mi2s_rx_ch; pr_debug("%s: format = %d rate = %d, channels = %d\n", __func__, params_format(params), params_rate(params), apq8084_mi2s_rx_ch); return 0; } static int apq8084_mi2s_rx_ch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s: apq8084_i2s_rx_ch = %d\n", __func__, apq8084_mi2s_rx_ch); ucontrol->value.integer.value[0] = apq8084_mi2s_rx_ch - 1; return 0; } static int apq8084_mi2s_rx_ch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { apq8084_mi2s_rx_ch = ucontrol->value.integer.value[0] + 1; pr_debug("%s: apq8084_i2s_rx_ch = %d\n", __func__, apq8084_mi2s_tx_ch); return 1; } static int msm_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { Loading Loading @@ -1504,6 +1870,8 @@ static const struct soc_enum msm_snd_enum[] = { SOC_ENUM_SINGLE_EXT(2, slim1_tx_ch_text), SOC_ENUM_SINGLE_EXT(3, slim1_rate_text), SOC_ENUM_SINGLE_EXT(3, slim3_rx_ch_text), SOC_ENUM_SINGLE_EXT(2, mi2s_rx_ch_text), SOC_ENUM_SINGLE_EXT(2, mi2s_tx_ch_text), }; static const struct snd_kcontrol_new msm_snd_controls[] = { Loading Loading @@ -1535,6 +1903,10 @@ static const struct snd_kcontrol_new msm_snd_controls[] = { msm_slim_3_rx_ch_get, msm_slim_3_rx_ch_put), SOC_SINGLE_EXT("Incall Rec Mode", SND_SOC_NOPM, 0, 1, 0, msm_incall_rec_mode_get, msm_incall_rec_mode_put), SOC_ENUM_EXT("QUAT_MI2S_RX Channels", msm_snd_enum[11], apq8084_mi2s_rx_ch_get, apq8084_mi2s_rx_ch_put), SOC_ENUM_EXT("QUAT_MI2S_TX Channels", msm_snd_enum[12], apq8084_mi2s_tx_ch_get, apq8084_mi2s_tx_ch_put), }; static bool apq8084_swap_gnd_mic(struct snd_soc_codec *codec) Loading Loading @@ -3027,6 +3399,34 @@ static struct snd_soc_dai_link apq8084_common_be_dai_links[] = { .ops = &apq8084_slimbus_6_be_ops, .ignore_suspend = 1, }, /* MI2S Backend DAI Links */ { .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, .be_id = MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, .be_hw_params_fixup = &apq8084_mi2s_rx_be_hw_params_fixup, .ops = &apq8084_quad_mi2s_be_ops, .ignore_suspend = 1, .ignore_pmdown_time = 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, .be_id = MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, .be_hw_params_fixup = &apq8084_mi2s_tx_be_hw_params_fixup, .ops = &apq8084_quad_mi2s_be_ops, .ignore_suspend = 1, }, }; static struct snd_soc_dai_link apq8084_tomtom_be_dai_links[] = { Loading Loading @@ -3345,6 +3745,65 @@ err: return ret; } /** * msm_mi2s_get_pinctrl() - Get the MI2S pinctrl definitions. * * @pdev: A pointer to the Audio platform device. * * Get the pinctrl states' handles from the device tree. The function doesn't * enforce wrong pinctrl definitions, i.e. it's the client's responsibility to * define all the necessary states for the board being used. * * Return 0 on success, error value otherwise. */ static int msm_mi2s_get_pinctrl(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); struct apq8084_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); struct msm_mi2s_pinctrl_info *pinctrl_info = &pdata->mi2s_pinctrl_info; struct pinctrl *pinctrl; int ret; pinctrl = devm_pinctrl_get(&pdev->dev); if (IS_ERR_OR_NULL(pinctrl)) { pr_err("%s: Unable to get pinctrl handle\n", __func__); return -EINVAL; } pinctrl_info->pinctrl = pinctrl; /* get all the states handles from Device Tree*/ pinctrl_info->disable = pinctrl_lookup_state(pinctrl, "pmx-quad-mi2s-sleep"); if (IS_ERR(pinctrl_info->disable)) { pr_err("%s: could not get disable pinstate\n", __func__); goto err; } pinctrl_info->quad_mi2s_active = pinctrl_lookup_state(pinctrl, "pmx-quad-mi2s-active"); if (IS_ERR(pinctrl_info->quad_mi2s_active)) { pr_err("%s: could not get quad_mi2s_active pinstate\n", __func__); goto err; } /* Reset the MI2S TLMM pins to a default state */ ret = pinctrl_select_state(pinctrl_info->pinctrl, pinctrl_info->disable); if (ret != 0) { pr_err("%s: Disable MI2S TLMM pins failed with %d\n", __func__, ret); return -EIO; } pinctrl_info->curr_mi2s_state = MI2S_STATE_DISABLE; return 0; err: devm_pinctrl_put(pinctrl); pinctrl_info->pinctrl = NULL; return -EINVAL; } static int apq8084_prepare_us_euro(struct snd_soc_card *card) { struct apq8084_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); Loading Loading @@ -3537,6 +3996,24 @@ static int apq8084_asoc_machine_probe(struct platform_device *pdev) goto err; } /* Parse pinctrl info for MI2S ports, if defined */ ret = msm_mi2s_get_pinctrl(pdev); if (!ret) { pr_debug("%s: MI2S pinctrl parsing successful\n", __func__); lpaif_quad_muxsel_virt_addr = ioremap(LPAIF_QUAD_MODE_MUXSEL, 4); if (lpaif_quad_muxsel_virt_addr == NULL) { pr_err("%s Quad MI2S mux virt addr is null\n", __func__); ret = -EINVAL; goto err; } } else { dev_info(&pdev->dev, "%s: Parsing pinctrl failed with %d. Cannot use MI2S Ports\n", __func__, ret); } pdata->us_euro_gpio = of_get_named_gpio(pdev->dev.of_node, "qcom,us-euro-gpios", 0); if (pdata->us_euro_gpio < 0) { Loading Loading @@ -3586,6 +4063,10 @@ static int apq8084_asoc_machine_probe(struct platform_device *pdev) return 0; err: if (pdata->mi2s_pinctrl_info.pinctrl) { dev_dbg(&pdev->dev, "%s: freeing MI2S pinctrl\n", __func__); devm_pinctrl_put(pdata->mi2s_pinctrl_info.pinctrl); } if (pdata->us_euro_gpio > 0) { dev_dbg(&pdev->dev, "%s free us_euro gpio %d\n", __func__, pdata->us_euro_gpio); Loading Loading
Documentation/devicetree/bindings/sound/qcom-audio-dev.txt +1 −1 Original line number Diff line number Diff line Loading @@ -1036,7 +1036,7 @@ Optional properties: - pinctrl-states: the names of the pinctrl states that used by the driver to configure the TLMM pins. The allowed states are subset of the following list: pmx-pri-mi2s-active, pmx-pri-quad-mi2s-active, pmx-quad-mi2s-active, pmx-pri-quad-mi2s-sleep. pmx-pri-quad-mi2s-sleep, pmx-quad-mi2s-sleep. - pinctrl-#: a list of pinctrl phandles for the different pinctrl states. Refer to "Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt" for the pinctrl handles definitions. Each pinctrl-# corresponds to the respective Loading
sound/soc/msm/apq8084.c +481 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,8 @@ static int slim0_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE; static int hdmi_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE; static int mi2s_tx_bit_format = SNDRV_PCM_FORMAT_S16_LE; static int mi2s_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE; #define SAMPLING_RATE_8KHZ 8000 #define SAMPLING_RATE_16KHZ 16000 Loading Loading @@ -147,11 +149,52 @@ struct msm_auxpcm_ctrl { u32 cnt; }; static const struct afe_clk_cfg lpass_default = { AFE_API_VERSION_I2S_CONFIG, Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ, Q6AFE_LPASS_OSR_CLK_DISABLE, Q6AFE_LPASS_CLK_SRC_INTERNAL, Q6AFE_LPASS_CLK_ROOT_DEFAULT, Q6AFE_LPASS_MODE_CLK1_VALID, 0, }; static const char *const mi2s_pin_states[] = {"Disable", "quad_mi2s_active"}; /* * enum mi2s_pin_state - states for the mi2s pinctrl states * Note: these states are similar to the "pinctrl-names" * in board/target specific DTSI file. */ enum mi2s_pin_state { MI2S_STATE_DISABLE = 0, MI2S_STATE_QUAD_ON = 1 }; /* * struct msm_mi2s_pinctrl_info - manage all the pinctrl information * * @pinctrl: TSC pinctrl state holder. * @disable: pinctrl state to disable all the pins. * @quad_mi2s_active: pinctrl state to activate Quaternary MI2S. * @curr_state: the current state of the TLMM pins. */ struct msm_mi2s_pinctrl_info { struct pinctrl *pinctrl; struct pinctrl_state *disable; struct pinctrl_state *quad_mi2s_active; enum mi2s_pin_state curr_mi2s_state; }; struct apq8084_asoc_mach_data { u32 mclk_freq; int us_euro_gpio; struct msm_auxpcm_ctrl *pri_auxpcm_ctrl; struct msm_auxpcm_ctrl *sec_auxpcm_ctrl; u32 quad_rx_clk_usrs; u32 quad_tx_clk_usrs; struct msm_mi2s_pinctrl_info mi2s_pinctrl_info; }; struct apq8084_asoc_wcd93xx_codec { Loading Loading @@ -185,6 +228,7 @@ static char *msm_sec_auxpcm_gpio_name[][2] = { void *lpaif_pri_muxsel_virt_addr; void *lpaif_sec_muxsel_virt_addr; void *lpaif_quad_muxsel_virt_addr; struct apq8084_liquid_dock_dev { int dock_plug_gpio; Loading Loading @@ -243,6 +287,12 @@ static int clk_users; static atomic_t prim_auxpcm_rsc_ref; static atomic_t sec_auxpcm_rsc_ref; static bool codec_reg_done; static int apq8084_mi2s_rx_ch = 1; static int apq8084_mi2s_tx_ch = 1; static atomic_t quad_mi2s_ref_count; static const char *const mi2s_tx_ch_text[] = {"One", "Two"}; static const char *const mi2s_rx_ch_text[] = {"One", "Two"}; static int apq8084_liquid_ext_spk_power_amp_init(void) { Loading Loading @@ -1289,6 +1339,322 @@ static struct snd_soc_ops msm_sec_auxpcm_be_ops = { .shutdown = msm_sec_auxpcm_shutdown, }; static int msm_quad_mi2s_set_pinctrl(struct apq8084_asoc_mach_data *pdata) { struct msm_mi2s_pinctrl_info *pinctrl_info = &pdata->mi2s_pinctrl_info; int ret = 0; pr_debug("%s: curr_mi2s_state = %s\n", __func__, mi2s_pin_states[pinctrl_info->curr_mi2s_state]); /* Enable Quaternary MI2S TLMM pins and set to appropriate state */ switch (pinctrl_info->curr_mi2s_state) { case MI2S_STATE_DISABLE: ret = pinctrl_select_state(pinctrl_info->pinctrl, pinctrl_info->quad_mi2s_active); if (ret) { pr_err("%s: pinctrl_select_state failed with %d\n", __func__, ret); ret = -EIO; goto err; } pinctrl_info->curr_mi2s_state = MI2S_STATE_QUAD_ON; break; case MI2S_STATE_QUAD_ON: pr_err("%s: MI2S TLMM pins already set\n", __func__); break; default: pr_err("%s: MI2S TLMM pin state is invalid\n", __func__); return -EINVAL; } err: return ret; } static int msm_quad_mi2s_reset_pinctrl(struct apq8084_asoc_mach_data *pdata) { struct msm_mi2s_pinctrl_info *pinctrl_info = &pdata->mi2s_pinctrl_info; int ret = 0; pr_debug("%s: curr_mi2s_state = %s\n", __func__, mi2s_pin_states[pinctrl_info->curr_mi2s_state]); /* Reset Quaternary MI2S TLMM pins and set to appropriate state */ switch (pinctrl_info->curr_mi2s_state) { case MI2S_STATE_QUAD_ON: ret = pinctrl_select_state(pinctrl_info->pinctrl, pinctrl_info->disable); if (ret) { pr_err("%s: pinctrl_select_state failed with %d\n", __func__, ret); ret = -EIO; goto err; } pinctrl_info->curr_mi2s_state = MI2S_STATE_DISABLE; break; case MI2S_STATE_DISABLE: pr_err("%s: MI2S TLMM pins already disabled\n", __func__); break; default: pr_err("%s: MI2S TLMM pin state is invalid\n", __func__); return -EINVAL; } err: return ret; } static int apq8084_quad_mi2s_clk_ctl(struct snd_soc_pcm_runtime *rtd, bool enable, struct snd_pcm_substream *substream) { struct snd_soc_card *card = rtd->card; struct apq8084_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); struct afe_clk_cfg *lpass_clk = NULL; int ret = 0; u32 afe_port_id; if (pdata == NULL) { pr_err("%s:platform data is null\n", __func__); return -EINVAL; } lpass_clk = kzalloc(sizeof(struct afe_clk_cfg), GFP_KERNEL); if (lpass_clk == NULL) { pr_err("%s:Failed to allocate memory\n", __func__); return -ENOMEM; } memcpy(lpass_clk, &lpass_default, sizeof(struct afe_clk_cfg)); pr_debug("%s: lpass clock enable = %d\n", __func__, enable); if (enable) { if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { afe_port_id = AFE_PORT_ID_QUATERNARY_MI2S_RX; if (pdata->quad_rx_clk_usrs == 0) { lpass_clk->clk_val1 = Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ; lpass_clk->clk_set_mode = Q6AFE_LPASS_MODE_CLK1_VALID; } ret = afe_set_lpass_clock(afe_port_id, lpass_clk); if (ret < 0) { pr_err("%s:afe_set_lpass_clock failed with %d\n", __func__, ret); goto err; } else { pdata->quad_rx_clk_usrs++; } } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { afe_port_id = AFE_PORT_ID_QUATERNARY_MI2S_TX; if (pdata->quad_tx_clk_usrs == 0) { lpass_clk->clk_val1 = Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ; lpass_clk->clk_set_mode = Q6AFE_LPASS_MODE_CLK1_VALID; } ret = afe_set_lpass_clock(afe_port_id, lpass_clk); if (ret < 0) { pr_err("%s:afe_set_lpass_clock failed with %d\n", __func__, ret); goto err; } else { pdata->quad_tx_clk_usrs++; } } } else { if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { afe_port_id = AFE_PORT_ID_QUATERNARY_MI2S_RX; if (pdata->quad_rx_clk_usrs > 0) pdata->quad_rx_clk_usrs--; if (pdata->quad_rx_clk_usrs == 0) { lpass_clk->clk_val1 = Q6AFE_LPASS_IBIT_CLK_DISABLE; lpass_clk->clk_set_mode = Q6AFE_LPASS_MODE_CLK1_VALID; } ret = afe_set_lpass_clock(afe_port_id, lpass_clk); if (ret < 0) { pr_err("%s:afe_set_lpass_clock failed with %d\n", __func__, ret); goto err; } } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { afe_port_id = AFE_PORT_ID_QUATERNARY_MI2S_TX; if (pdata->quad_tx_clk_usrs > 0) pdata->quad_tx_clk_usrs--; if (pdata->quad_tx_clk_usrs == 0) { lpass_clk->clk_val1 = Q6AFE_LPASS_IBIT_CLK_DISABLE; lpass_clk->clk_set_mode = Q6AFE_LPASS_MODE_CLK1_VALID; } ret = afe_set_lpass_clock(afe_port_id, lpass_clk); if (ret < 0) { pr_err("%s:afe_set_lpass_clock failed with %d\n", __func__, ret); goto err; } } } pr_debug("%s: clk 1 = 0x%x clk2 = 0x%x mode = 0x%x\n", __func__, lpass_clk->clk_val1, lpass_clk->clk_val2, lpass_clk->clk_set_mode); ret = 0; err: kfree(lpass_clk); return ret; } static int msm_quad_mi2s_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_card *card = rtd->card; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct apq8084_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); int ret = 0; uint32_t pcm_sel_reg; pr_debug("%s(): substream = %s, quad_mi2s_ref_count = %d\n", __func__, substream->name, atomic_read(&quad_mi2s_ref_count)); if (pdata == NULL || lpaif_quad_muxsel_virt_addr == NULL) { pr_err("%s: Invalid parameters for Quad MI2S\n", __func__); ret = -EINVAL; goto err; } if (atomic_inc_return(&quad_mi2s_ref_count) == 1) { pcm_sel_reg = ioread32(lpaif_quad_muxsel_virt_addr); if (pcm_sel_reg & (I2S_PCM_SEL << I2S_PCM_SEL_OFFSET)) { iowrite32(pcm_sel_reg & ~(I2S_PCM_SEL << I2S_PCM_SEL_OFFSET), lpaif_quad_muxsel_virt_addr); } ret = msm_quad_mi2s_set_pinctrl(pdata); if (ret) { pr_err("%s: MI2S TLMM pinctrl set failed with %d\n", __func__, ret); return ret; } ret = apq8084_quad_mi2s_clk_ctl(rtd, true, substream); if (ret) { pr_err("%s: Setting clk control failed with %d\n", __func__, ret); return ret; } /* This sets the CONFIG PARAMETER WS_SRC. * SND_SOC_DAIFMT_CBS_CFS means internal clock/master mode. * SND_SOC_DAIFMT_CBM_CFM means external clock/slave mode. */ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS); if (ret) pr_err("%s: set fmt cpu dai failed with %d\n", __func__, ret); } err: return ret; } static void msm_quad_mi2s_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_card *card = rtd->card; struct apq8084_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); int ret; pr_debug("%s(): substream = %s, quad_mi2s_ref_count = %d\n", __func__, substream->name, atomic_read(&quad_mi2s_ref_count)); if (pdata == NULL) { pr_err("%s: Invalid platform data\n", __func__); return; } if (atomic_dec_return(&quad_mi2s_ref_count) == 0) { ret = msm_quad_mi2s_reset_pinctrl(pdata); if (ret) pr_err("%s Reset pinctrl failed with %d\n", __func__, ret); ret = apq8084_quad_mi2s_clk_ctl(rtd, false, substream); if (ret) pr_err("%s Clock disable failed with %d\n", __func__, ret); } } static struct snd_soc_ops apq8084_quad_mi2s_be_ops = { .startup = msm_quad_mi2s_startup, .shutdown = msm_quad_mi2s_shutdown, }; static int apq8084_mi2s_tx_be_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); param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, mi2s_tx_bit_format); rate->min = rate->max = SAMPLING_RATE_48KHZ; channels->min = channels->max = apq8084_mi2s_tx_ch; pr_debug("%s: format = %d rate = %d, channels = %d\n", __func__, params_format(params), params_rate(params), apq8084_mi2s_tx_ch); return 0; } static int apq8084_mi2s_tx_ch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s: apq8084_i2s_tx_ch = %d\n", __func__, apq8084_mi2s_tx_ch); ucontrol->value.integer.value[0] = apq8084_mi2s_tx_ch - 1; return 0; } static int apq8084_mi2s_tx_ch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { apq8084_mi2s_tx_ch = ucontrol->value.integer.value[0] + 1; pr_debug("%s: apq8084_i2s_tx_ch = %d\n", __func__, apq8084_mi2s_tx_ch); return 1; } static int apq8084_mi2s_rx_be_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); param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, mi2s_rx_bit_format); rate->min = rate->max = SAMPLING_RATE_48KHZ; channels->min = channels->max = apq8084_mi2s_rx_ch; pr_debug("%s: format = %d rate = %d, channels = %d\n", __func__, params_format(params), params_rate(params), apq8084_mi2s_rx_ch); return 0; } static int apq8084_mi2s_rx_ch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { pr_debug("%s: apq8084_i2s_rx_ch = %d\n", __func__, apq8084_mi2s_rx_ch); ucontrol->value.integer.value[0] = apq8084_mi2s_rx_ch - 1; return 0; } static int apq8084_mi2s_rx_ch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { apq8084_mi2s_rx_ch = ucontrol->value.integer.value[0] + 1; pr_debug("%s: apq8084_i2s_rx_ch = %d\n", __func__, apq8084_mi2s_tx_ch); return 1; } static int msm_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { Loading Loading @@ -1504,6 +1870,8 @@ static const struct soc_enum msm_snd_enum[] = { SOC_ENUM_SINGLE_EXT(2, slim1_tx_ch_text), SOC_ENUM_SINGLE_EXT(3, slim1_rate_text), SOC_ENUM_SINGLE_EXT(3, slim3_rx_ch_text), SOC_ENUM_SINGLE_EXT(2, mi2s_rx_ch_text), SOC_ENUM_SINGLE_EXT(2, mi2s_tx_ch_text), }; static const struct snd_kcontrol_new msm_snd_controls[] = { Loading Loading @@ -1535,6 +1903,10 @@ static const struct snd_kcontrol_new msm_snd_controls[] = { msm_slim_3_rx_ch_get, msm_slim_3_rx_ch_put), SOC_SINGLE_EXT("Incall Rec Mode", SND_SOC_NOPM, 0, 1, 0, msm_incall_rec_mode_get, msm_incall_rec_mode_put), SOC_ENUM_EXT("QUAT_MI2S_RX Channels", msm_snd_enum[11], apq8084_mi2s_rx_ch_get, apq8084_mi2s_rx_ch_put), SOC_ENUM_EXT("QUAT_MI2S_TX Channels", msm_snd_enum[12], apq8084_mi2s_tx_ch_get, apq8084_mi2s_tx_ch_put), }; static bool apq8084_swap_gnd_mic(struct snd_soc_codec *codec) Loading Loading @@ -3027,6 +3399,34 @@ static struct snd_soc_dai_link apq8084_common_be_dai_links[] = { .ops = &apq8084_slimbus_6_be_ops, .ignore_suspend = 1, }, /* MI2S Backend DAI Links */ { .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, .be_id = MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, .be_hw_params_fixup = &apq8084_mi2s_rx_be_hw_params_fixup, .ops = &apq8084_quad_mi2s_be_ops, .ignore_suspend = 1, .ignore_pmdown_time = 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, .be_id = MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, .be_hw_params_fixup = &apq8084_mi2s_tx_be_hw_params_fixup, .ops = &apq8084_quad_mi2s_be_ops, .ignore_suspend = 1, }, }; static struct snd_soc_dai_link apq8084_tomtom_be_dai_links[] = { Loading Loading @@ -3345,6 +3745,65 @@ err: return ret; } /** * msm_mi2s_get_pinctrl() - Get the MI2S pinctrl definitions. * * @pdev: A pointer to the Audio platform device. * * Get the pinctrl states' handles from the device tree. The function doesn't * enforce wrong pinctrl definitions, i.e. it's the client's responsibility to * define all the necessary states for the board being used. * * Return 0 on success, error value otherwise. */ static int msm_mi2s_get_pinctrl(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); struct apq8084_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); struct msm_mi2s_pinctrl_info *pinctrl_info = &pdata->mi2s_pinctrl_info; struct pinctrl *pinctrl; int ret; pinctrl = devm_pinctrl_get(&pdev->dev); if (IS_ERR_OR_NULL(pinctrl)) { pr_err("%s: Unable to get pinctrl handle\n", __func__); return -EINVAL; } pinctrl_info->pinctrl = pinctrl; /* get all the states handles from Device Tree*/ pinctrl_info->disable = pinctrl_lookup_state(pinctrl, "pmx-quad-mi2s-sleep"); if (IS_ERR(pinctrl_info->disable)) { pr_err("%s: could not get disable pinstate\n", __func__); goto err; } pinctrl_info->quad_mi2s_active = pinctrl_lookup_state(pinctrl, "pmx-quad-mi2s-active"); if (IS_ERR(pinctrl_info->quad_mi2s_active)) { pr_err("%s: could not get quad_mi2s_active pinstate\n", __func__); goto err; } /* Reset the MI2S TLMM pins to a default state */ ret = pinctrl_select_state(pinctrl_info->pinctrl, pinctrl_info->disable); if (ret != 0) { pr_err("%s: Disable MI2S TLMM pins failed with %d\n", __func__, ret); return -EIO; } pinctrl_info->curr_mi2s_state = MI2S_STATE_DISABLE; return 0; err: devm_pinctrl_put(pinctrl); pinctrl_info->pinctrl = NULL; return -EINVAL; } static int apq8084_prepare_us_euro(struct snd_soc_card *card) { struct apq8084_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); Loading Loading @@ -3537,6 +3996,24 @@ static int apq8084_asoc_machine_probe(struct platform_device *pdev) goto err; } /* Parse pinctrl info for MI2S ports, if defined */ ret = msm_mi2s_get_pinctrl(pdev); if (!ret) { pr_debug("%s: MI2S pinctrl parsing successful\n", __func__); lpaif_quad_muxsel_virt_addr = ioremap(LPAIF_QUAD_MODE_MUXSEL, 4); if (lpaif_quad_muxsel_virt_addr == NULL) { pr_err("%s Quad MI2S mux virt addr is null\n", __func__); ret = -EINVAL; goto err; } } else { dev_info(&pdev->dev, "%s: Parsing pinctrl failed with %d. Cannot use MI2S Ports\n", __func__, ret); } pdata->us_euro_gpio = of_get_named_gpio(pdev->dev.of_node, "qcom,us-euro-gpios", 0); if (pdata->us_euro_gpio < 0) { Loading Loading @@ -3586,6 +4063,10 @@ static int apq8084_asoc_machine_probe(struct platform_device *pdev) return 0; err: if (pdata->mi2s_pinctrl_info.pinctrl) { dev_dbg(&pdev->dev, "%s: freeing MI2S pinctrl\n", __func__); devm_pinctrl_put(pdata->mi2s_pinctrl_info.pinctrl); } if (pdata->us_euro_gpio > 0) { dev_dbg(&pdev->dev, "%s free us_euro gpio %d\n", __func__, pdata->us_euro_gpio); Loading