Merge "asoc: sdm660: Add startup and shutdown functions for TDM"
diff --git a/asoc/sdm660-common.c b/asoc/sdm660-common.c
index 093eef4..b2cbc2a 100644
--- a/asoc/sdm660-common.c
+++ b/asoc/sdm660-common.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -51,6 +51,18 @@
bool codec_reg_done;
+struct tdm_dai_data {
+ DECLARE_BITMAP(status_mask, 3);
+ u32 rate;
+ u32 channels;
+ u32 bitwidth;
+ u32 num_group_ports;
+ struct afe_clk_set clk_set; /* hold LPASS clock config. */
+ union afe_port_group_config group_cfg; /* hold tdm group config */
+ struct afe_tdm_port_config port_cfg; /* hold tdm config */
+};
+
+
/* TDM default config */
static struct dev_config tdm_rx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = {
{ /* PRI TDM */
@@ -2803,6 +2815,91 @@
}
EXPORT_SYMBOL(msm_mi2s_snd_shutdown);
+static int msm_get_tdm_mode(u32 port_id)
+{
+ int tdm_mode;
+
+ switch (port_id) {
+ case AFE_PORT_ID_PRIMARY_TDM_RX:
+ case AFE_PORT_ID_PRIMARY_TDM_TX:
+ tdm_mode = TDM_PRI;
+ break;
+ case AFE_PORT_ID_SECONDARY_TDM_RX:
+ case AFE_PORT_ID_SECONDARY_TDM_TX:
+ tdm_mode = TDM_SEC;
+ break;
+ case AFE_PORT_ID_TERTIARY_TDM_RX:
+ case AFE_PORT_ID_TERTIARY_TDM_TX:
+ tdm_mode = TDM_TERT;
+ break;
+ case AFE_PORT_ID_QUATERNARY_TDM_RX:
+ case AFE_PORT_ID_QUATERNARY_TDM_TX:
+ tdm_mode = TDM_QUAT;
+ break;
+ case AFE_PORT_ID_QUINARY_TDM_RX:
+ case AFE_PORT_ID_QUINARY_TDM_TX:
+ tdm_mode = TDM_QUIN;
+ break;
+ default:
+ pr_err("%s: Invalid port id: %d\n", __func__, port_id);
+ tdm_mode = -EINVAL;
+ }
+ return tdm_mode;
+}
+
+int msm_tdm_snd_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;
+ struct snd_soc_card *card = rtd->card;
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ struct tdm_dai_data *dai_data = dev_get_drvdata(cpu_dai->dev);
+ int tdm_mode = msm_get_tdm_mode(cpu_dai->id);
+
+ if (tdm_mode < 0) {
+ dev_err(rtd->card->dev, "%s: Invalid tdm_mode\n", __func__);
+ return tdm_mode;
+ }
+ dai_data->clk_set.enable = true;
+ ret = afe_set_lpass_clock_v2(cpu_dai->id, &dai_data->clk_set);
+ if (ret < 0)
+ pr_err("%s: afe lpass clock failed, err:%d\n",
+ __func__, ret);
+ /* currently only supporting TDM_RX_0 and TDM_TX_0 */
+ if (pdata->mi2s_gpio_p[tdm_mode])
+ ret = msm_cdc_pinctrl_select_active_state(
+ pdata->mi2s_gpio_p[tdm_mode]);
+ return ret;
+}
+EXPORT_SYMBOL(msm_tdm_snd_startup);
+
+void msm_tdm_snd_shutdown(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_card *card = rtd->card;
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ struct tdm_dai_data *dai_data = dev_get_drvdata(cpu_dai->dev);
+ int tdm_mode = msm_get_tdm_mode(cpu_dai->id);
+ int ret;
+
+ if (tdm_mode < 0) {
+ dev_err(rtd->card->dev, "%s: Invalid tdm_mode\n", __func__);
+ return;
+ }
+ dai_data->clk_set.enable = false;
+ ret = afe_set_lpass_clock_v2(cpu_dai->id, &dai_data->clk_set);
+ if (ret < 0)
+ pr_err("%s: afe lpass clock failed, err:%d\n", __func__, ret);
+
+ /* currently only supporting TDM_RX_0 and TDM_TX_0 */
+ if (pdata->mi2s_gpio_p[tdm_mode])
+ msm_cdc_pinctrl_select_sleep_state(
+ pdata->mi2s_gpio_p[tdm_mode]);
+}
+EXPORT_SYMBOL(msm_tdm_snd_shutdown);
+
/* Validate whether US EU switch is present or not */
static int msm_prepare_us_euro(struct snd_soc_card *card)
{
diff --git a/asoc/sdm660-common.h b/asoc/sdm660-common.h
index 3df6bf8..418bbf6 100644
--- a/asoc/sdm660-common.h
+++ b/asoc/sdm660-common.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -134,6 +134,8 @@
void msm_aux_pcm_snd_shutdown(struct snd_pcm_substream *substream);
int msm_mi2s_snd_startup(struct snd_pcm_substream *substream);
void msm_mi2s_snd_shutdown(struct snd_pcm_substream *substream);
+int msm_tdm_snd_startup(struct snd_pcm_substream *substream);
+void msm_tdm_snd_shutdown(struct snd_pcm_substream *substream);
int msm_common_snd_controls_size(void);
void msm_set_codec_reg_done(bool done);
#endif
diff --git a/asoc/sdm660-ext-dai-links.c b/asoc/sdm660-ext-dai-links.c
index 3568ebb..66182dd 100644
--- a/asoc/sdm660-ext-dai-links.c
+++ b/asoc/sdm660-ext-dai-links.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -278,7 +278,9 @@
}
static struct snd_soc_ops msm_tdm_be_ops = {
- .hw_params = msm_tdm_snd_hw_params
+ .startup = msm_tdm_snd_startup,
+ .shutdown = msm_tdm_snd_shutdown,
+ .hw_params = msm_tdm_snd_hw_params,
};
static int msm_fe_qos_prepare(struct snd_pcm_substream *substream)
diff --git a/asoc/sdm660-internal.c b/asoc/sdm660-internal.c
index ebcea54..b35179a 100644
--- a/asoc/sdm660-internal.c
+++ b/asoc/sdm660-internal.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -1890,7 +1890,9 @@
}
static struct snd_soc_ops msm_tdm_be_ops = {
- .hw_params = msm_tdm_snd_hw_params
+ .startup = msm_tdm_snd_startup,
+ .shutdown = msm_tdm_snd_shutdown,
+ .hw_params = msm_tdm_snd_hw_params,
};
static struct snd_soc_ops msm_wcn_ops = {