summaryrefslogtreecommitdiff
path: root/sound/soc/msm
diff options
context:
space:
mode:
authorBanajit Goswami <bgoswami@codeaurora.org>2016-04-08 19:49:50 -0700
committerJeevan Shriram <jshriram@codeaurora.org>2016-05-06 12:06:25 -0700
commit34ec6c6739b193bffe29a71b1f36c912776e1b5e (patch)
tree883fd37d17317acaad548ffbcec42e7074ff4d62 /sound/soc/msm
parent935421afd31326334b1249c0d16a2ea693f36614 (diff)
ASoC: msmcobalt: add BT/FM audio support with WCN3990
Add machine driver code to support audio on MSMCOBALT based boards with WCN3990 BT/FM chipset. Change-Id: Ia23572f44775a04c8f8c67e9a61d6b9be8869b82 Signed-off-by: Banajit Goswami <bgoswami@codeaurora.org>
Diffstat (limited to 'sound/soc/msm')
-rw-r--r--sound/soc/msm/msmcobalt.c211
1 files changed, 205 insertions, 6 deletions
diff --git a/sound/soc/msm/msmcobalt.c b/sound/soc/msm/msmcobalt.c
index 9f3f72a46575..87d72db72a35 100644
--- a/sound/soc/msm/msmcobalt.c
+++ b/sound/soc/msm/msmcobalt.c
@@ -58,6 +58,9 @@
#define WSA8810_NAME_1 "wsa881x.20170211"
#define WSA8810_NAME_2 "wsa881x.20170212"
+#define WCN_CDC_SLIM_RX_CH_MAX 2
+#define WCN_CDC_SLIM_TX_CH_MAX 3
+
enum {
SLIM_RX_0 = 0,
SLIM_RX_1,
@@ -65,6 +68,7 @@ enum {
SLIM_RX_3,
SLIM_RX_4,
SLIM_RX_5,
+ SLIM_RX_7,
SLIM_RX_MAX,
};
@@ -77,6 +81,7 @@ enum {
SLIM_TX_5,
SLIM_TX_6,
SLIM_TX_7,
+ SLIM_TX_8,
SLIM_TX_MAX,
};
@@ -113,6 +118,7 @@ static struct slim_ch_config slim_rx_cfg[] = {
[SLIM_RX_3] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
[SLIM_RX_4] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
[SLIM_RX_5] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_RX_7] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
};
static struct slim_ch_config slim_tx_cfg[] = {
@@ -123,7 +129,8 @@ static struct slim_ch_config slim_tx_cfg[] = {
[SLIM_TX_4] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
[SLIM_TX_5] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
[SLIM_TX_6] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
- [SLIM_TX_7] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_TX_7] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
+ [SLIM_TX_8] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
};
static int msm_vi_feed_tx_ch = 2;
@@ -136,6 +143,7 @@ static char const *bit_format_text[] = {"S16_LE", "S24_LE"};
static char const *slim_sample_rate_text[] = {"KHZ_8", "KHZ_16",
"KHZ_32", "KHZ_44P1", "KHZ_48",
"KHZ_96", "KHZ_192"};
+static char const *bt_sco_sample_rate_text[] = {"KHZ_8", "KHZ_16"};
static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_chs, slim_rx_ch_text);
static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_chs, slim_tx_ch_text);
@@ -148,6 +156,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_format, bit_format_text);
static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_sample_rate, slim_sample_rate_text);
static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_sample_rate, slim_sample_rate_text);
static SOC_ENUM_SINGLE_EXT_DECL(slim_5_rx_sample_rate, slim_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(bt_sco_sample_rate, bt_sco_sample_rate_text);
static struct platform_device *spdev;
@@ -541,6 +550,44 @@ static int msm_vi_feed_tx_ch_put(struct snd_kcontrol *kcontrol,
return 1;
}
+static int msm_bt_sco_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ /*
+ * Slimbus_7_Rx/Tx sample rate values should always be in sync (same)
+ * when used for BT_SCO use case. Return either Rx or Tx sample rate
+ * value.
+ */
+ ucontrol->value.integer.value[0] = slim_rx_cfg[SLIM_RX_7].sample_rate;
+ pr_debug("%s: sample rate = %d", __func__,
+ slim_rx_cfg[SLIM_RX_7].sample_rate);
+
+ return 0;
+}
+
+static int msm_bt_sco_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 1:
+ slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_16KHZ;
+ slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_16KHZ;
+ break;
+ case 0:
+ default:
+ slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_8KHZ;
+ slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_8KHZ;
+ break;
+ }
+ pr_debug("%s: sample rates: slim7_rx = %d, slim7_tx = %d, value = %d\n",
+ __func__,
+ slim_rx_cfg[SLIM_RX_7].sample_rate,
+ slim_tx_cfg[SLIM_TX_7].sample_rate,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
static const struct snd_kcontrol_new msm_snd_controls[] = {
SOC_ENUM_EXT("SLIM_0_RX Channels", slim_0_rx_chs,
msm_slim_rx_ch_get, msm_slim_rx_ch_put),
@@ -564,6 +611,9 @@ static const struct snd_kcontrol_new msm_snd_controls[] = {
slim_tx_sample_rate_get, slim_tx_sample_rate_put),
SOC_ENUM_EXT("SLIM_5_RX SampleRate", slim_5_rx_sample_rate,
slim_rx_sample_rate_get, slim_rx_sample_rate_put),
+ SOC_ENUM_EXT("BT_SCO SampleRate", bt_sco_sample_rate,
+ msm_bt_sco_sample_rate_get,
+ msm_bt_sco_sample_rate_put),
};
static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec,
@@ -718,6 +768,24 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
}
break;
+ case MSM_BACKEND_DAI_SLIMBUS_7_RX:
+ rate->min = rate->max = slim_rx_cfg[SLIM_RX_7].sample_rate;
+ channels->min = channels->max =
+ slim_rx_cfg[SLIM_RX_7].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SLIMBUS_7_TX:
+ rate->min = rate->max = slim_tx_cfg[SLIM_TX_7].sample_rate;
+ channels->min = channels->max =
+ slim_tx_cfg[SLIM_TX_7].channels;
+ break;
+
+ case MSM_BACKEND_DAI_SLIMBUS_8_TX:
+ rate->min = rate->max = slim_tx_cfg[SLIM_TX_8].sample_rate;
+ channels->min = channels->max =
+ slim_tx_cfg[SLIM_TX_8].channels;
+ break;
+
default:
rate->min = rate->max = SAMPLING_RATE_48KHZ;
break;
@@ -1054,6 +1122,16 @@ err_afe_cfg:
return ret;
}
+static int msm_wcn_init(struct snd_soc_pcm_runtime *rtd)
+{
+ unsigned int rx_ch[WCN_CDC_SLIM_RX_CH_MAX] = {157, 158};
+ unsigned int tx_ch[WCN_CDC_SLIM_TX_CH_MAX] = {159, 160, 161};
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+ return snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
+ tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
+}
+
static void *def_tasha_mbhc_cal(void)
{
void *tasha_wcd_cal;
@@ -1262,6 +1340,41 @@ err_ch_map:
return ret;
}
+static int msm_wcn_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
+ u32 rx_ch[WCN_CDC_SLIM_RX_CH_MAX], tx_ch[WCN_CDC_SLIM_TX_CH_MAX];
+ u32 rx_ch_cnt = 0, tx_ch_cnt = 0;
+ int ret;
+
+ dev_dbg(rtd->dev, "%s: %s_tx_dai_id_%d\n", __func__,
+ codec_dai->name, codec_dai->id);
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
+ if (ret) {
+ dev_err(rtd->dev,
+ "%s: failed to get BTFM codec chan map\n, err:%d\n",
+ __func__, ret);
+ goto exit;
+ }
+
+ dev_dbg(rtd->dev, "%s: tx_ch_cnt(%d) be_id %d\n",
+ __func__, tx_ch_cnt, dai_link->be_id);
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ tx_ch_cnt, tx_ch, rx_ch_cnt, rx_ch);
+ if (ret)
+ dev_err(rtd->dev, "%s: failed to set cpu chan map, err:%d\n",
+ __func__, ret);
+
+exit:
+ return ret;
+}
+
static struct snd_soc_ops msm_be_ops = {
.hw_params = msm_snd_hw_params,
};
@@ -1274,6 +1387,10 @@ static struct snd_soc_ops msm_slimbus_2_be_ops = {
.hw_params = msm_slimbus_2_hw_params,
};
+static struct snd_soc_ops msm_wcn_ops = {
+ .hw_params = msm_wcn_hw_params,
+};
+
static int msm_get_ll_qos_val(struct snd_pcm_runtime *runtime)
{
int usecs;
@@ -1859,6 +1976,21 @@ static struct snd_soc_dai_link msm_common_dai_links[] = {
/* this dainlink has playback support */
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA16,
},
+ {
+ .name = "SLIMBUS_8 Hostless",
+ .stream_name = "SLIMBUS8_HOSTLESS Capture",
+ .cpu_dai_name = "SLIMBUS8_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
};
static struct snd_soc_dai_link msm_tasha_fe_dai_links[] = {
@@ -2145,11 +2277,60 @@ static struct snd_soc_dai_link msm_tasha_be_dai_links[] = {
},
};
+static struct snd_soc_dai_link msm_wcn_be_dai_links[] = {
+ {
+ .name = LPASS_BE_SLIMBUS_7_RX,
+ .stream_name = "Slimbus7 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16398",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "btfmslim_slave",
+ .codec_dai_name = "btfm_bt_sco_slim_rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_7_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_wcn_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_7_TX,
+ .stream_name = "Slimbus7 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16399",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "btfmslim_slave",
+ .codec_dai_name = "btfm_bt_sco_slim_tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_7_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_wcn_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_8_TX,
+ .stream_name = "Slimbus8 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16401",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "btfmslim_slave",
+ .codec_dai_name = "btfm_fm_slim_tx",
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_8_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .init = &msm_wcn_init,
+ .ops = &msm_wcn_ops,
+ .ignore_suspend = 1,
+ },
+};
+
static struct snd_soc_dai_link msm_tasha_dai_links[
ARRAY_SIZE(msm_common_dai_links) +
ARRAY_SIZE(msm_tasha_fe_dai_links) +
ARRAY_SIZE(msm_common_be_dai_links) +
- ARRAY_SIZE(msm_tasha_be_dai_links)];
+ ARRAY_SIZE(msm_tasha_be_dai_links) +
+ ARRAY_SIZE(msm_wcn_be_dai_links)];
static int msm_snd_card_late_probe(struct snd_soc_card *card)
{
@@ -2467,7 +2648,9 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
struct snd_soc_card *card = NULL;
struct snd_soc_dai_link *dailink;
int len_1, len_2, len_3, len_4;
+ int total_links;
const struct of_device_id *match;
+ bool use_wcn_btfm = false;
match = of_match_node(msmcobalt_asoc_machine_of_match, dev->of_node);
if (!match) {
@@ -2476,11 +2659,25 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
return NULL;
}
+ if (of_property_read_bool(dev->of_node, "qcom,wcn-btfm")) {
+ use_wcn_btfm = true;
+ dev_dbg(dev, "%s(): WCN BTFM support present\n", __func__);
+ } else {
+ dev_dbg(dev, "%s(): No WCN BTFM support\n", __func__);
+ }
+
if (!strcmp(match->data, "tasha_codec")) {
card = &snd_soc_card_tasha_msm;
len_1 = ARRAY_SIZE(msm_common_dai_links);
len_2 = len_1 + ARRAY_SIZE(msm_tasha_fe_dai_links);
len_3 = len_2 + ARRAY_SIZE(msm_common_be_dai_links);
+ len_4 = len_3 + ARRAY_SIZE(msm_tasha_be_dai_links);
+ if (use_wcn_btfm) {
+ total_links = len_4 +
+ ARRAY_SIZE(msm_wcn_be_dai_links);
+ } else {
+ total_links = len_4;
+ }
memcpy(msm_tasha_dai_links,
msm_common_dai_links,
@@ -2494,10 +2691,12 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
memcpy(msm_tasha_dai_links + len_3,
msm_tasha_be_dai_links,
sizeof(msm_tasha_be_dai_links));
+ if (use_wcn_btfm)
+ memcpy(msm_tasha_dai_links + len_4,
+ msm_wcn_be_dai_links,
+ sizeof(msm_wcn_be_dai_links));
dailink = msm_tasha_dai_links;
- len_4 = len_3 + ARRAY_SIZE(msm_tasha_be_dai_links);
-
} else if (!strcmp(match->data, "stub_codec")) {
card = &snd_soc_card_stub_msm;
len_1 = ARRAY_SIZE(msm_stub_fe_dai_links);
@@ -2511,13 +2710,13 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
sizeof(msm_stub_be_dai_links));
dailink = msm_stub_dai_links;
- len_4 = len_2;
+ total_links = len_2;
}
dev_dbg(dev, "%s(): No hdmi audio support\n", __func__);
if (card) {
card->dai_link = dailink;
- card->num_links = len_4;
+ card->num_links = total_links;
}
return card;