From f7d9f43f02d3d2838a55414d15367dc91c1ce00a Mon Sep 17 00:00:00 2001 From: Honghao Liu Date: Wed, 8 Mar 2017 16:36:35 -0500 Subject: [PATCH] ASoC: msm: add support for customized sound card Add support for customized sound card that uses customized TDM slot mapping and DAI links for automotive platform. CRs-fixed: 2020063 Change-Id: I887b33d23d2af8af61cf15b499d14afbc9544e37 Signed-off-by: Honghao Liu --- .../bindings/sound/qcom-audio-dev.txt | 4 +- sound/soc/msm/apq8096-auto.c | 291 ++++++++++++++++-- 2 files changed, 270 insertions(+), 25 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt index 6f0d99d560cd..acf12239c813 100644 --- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt +++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt @@ -2107,7 +2107,9 @@ Required properties: "qcom,apq8096-asoc-snd-adp-agave" for adp agave codec and node is "sound-adp-agave", "qcom,apq8096-asoc-snd-adp-mmxf" for adp mmxf codec and - node is "sound-adp-mmxf". + node is "sound-adp-mmxf", + "qcom,apq8096-asoc-snd-auto-custom" for auto custom codec and + node is "sound-auto-custom". - qcom,model : The user-visible name of this sound card. - asoc-platform: This is phandle list containing the references to platform device nodes that are used as part of the sound card dai-links. diff --git a/sound/soc/msm/apq8096-auto.c b/sound/soc/msm/apq8096-auto.c index 138f4a02452c..94367b5f680b 100644 --- a/sound/soc/msm/apq8096-auto.c +++ b/sound/soc/msm/apq8096-auto.c @@ -115,6 +115,9 @@ static int msm_ec_ref_ch = 4; static int msm_ec_ref_bit_format = SNDRV_PCM_FORMAT_S16_LE; static int msm_ec_ref_sampling_rate = SAMPLING_RATE_48KHZ; +static int msm_tdm_slot_width = 32; +static int msm_tdm_num_slots = 8; + static void *adsp_state_notifier; static bool dummy_device_registered; @@ -295,6 +298,62 @@ static unsigned int tdm_slot_offset_adp_mmxf[TDM_MAX][TDM_SLOT_OFFSET_MAX] = { {0xFFFF}, /* not used */ }; +static unsigned int tdm_slot_offset_custom[TDM_MAX][TDM_SLOT_OFFSET_MAX] = { + /* QUAT_TDM_RX */ + {0, 2, 0xFFFF}, + {4, 6, 8, 10, 12, 14, 16, 18}, + {20, 22, 24, 26, 28, 30, 0xFFFF}, + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + /* QUAT_TDM_TX */ + {0, 2, 0xFFFF}, + {4, 6, 8, 10, 12, 14, 16, 18}, + {20, 22, 24, 26, 28, 30, 0xFFFF}, + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + /* TERT_TDM_RX */ + {0, 2, 0xFFFF}, + {4, 0xFFFF}, + {6, 0xFFFF}, + {8, 0xFFFF}, + {10, 0xFFFF}, + {12, 14, 16, 18, 20, 22, 24, 26}, + {28, 30, 0xFFFF}, + {0xFFFF}, /* not used */ + /* TERT_TDM_TX */ + {0, 2, 4, 6, 8, 10, 12, 0xFFFF}, + {14, 16, 0xFFFF}, + {18, 20, 22, 24, 26, 28, 30, 0xFFFF}, + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + /* SEC_TDM_RX */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + /* SEC_TDM_TX */ + {0xFFFF}, + {0xFFFF}, + {0xFFFF}, + {0xFFFF}, + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ + {0xFFFF}, /* not used */ +}; static char const *hdmi_rx_ch_text[] = {"Two", "Three", "Four", "Five", "Six", "Seven", "Eight"}; @@ -2272,14 +2331,14 @@ static int apq8096_tdm_snd_hw_params(struct snd_pcm_substream *substream, * use 32 bit slot width for max support of * stream bit width. (slot_width > bit_width) */ - slot_width = 32; + slot_width = msm_tdm_slot_width; break; default: pr_err("%s: invalid param format 0x%x\n", __func__, params_format(params)); return -EINVAL; } - slots = 8; + slots = msm_tdm_num_slots; slot_mask = tdm_param_set_slot_mask(cpu_dai->id, slot_width, slots); if (!slot_mask) { @@ -2660,7 +2719,7 @@ static int apq8096_get_ll_qos_val(struct snd_pcm_runtime *runtime) return usecs; } -static int apq8096_mm5_prepare(struct snd_pcm_substream *substream) +static int apq8096_ll_prepare(struct snd_pcm_substream *substream) { if (pm_qos_request_active(&substream->latency_pm_qos_req)) pm_qos_remove_request(&substream->latency_pm_qos_req); @@ -2670,8 +2729,8 @@ static int apq8096_mm5_prepare(struct snd_pcm_substream *substream) return 0; } -static struct snd_soc_ops apq8096_mm5_ops = { - .prepare = apq8096_mm5_prepare, +static struct snd_soc_ops apq8096_ll_ops = { + .prepare = apq8096_ll_prepare, }; /* Digital audio interface glue - connects codec <---> CPU */ @@ -2938,7 +2997,7 @@ static struct snd_soc_dai_link apq8096_common_dai_links[] = { /* this dainlink has playback support */ .ignore_pmdown_time = 1, .be_id = MSM_FRONTEND_DAI_MULTIMEDIA5, - .ops = &apq8096_mm5_ops, + .ops = &apq8096_ll_ops, }, { .name = "Listen 1 Audio Service", @@ -3647,6 +3706,143 @@ static struct snd_soc_dai_link apq8096_auto_fe_dai_links[] = { }, }; +static struct snd_soc_dai_link apq8096_custom_fe_dai_links[] = { + /* FrontEnd DAI Links */ + { + .name = "MSM8996 Media1", + .stream_name = "MultiMedia1", + .cpu_dai_name = "MultiMedia1", + .platform_name = "msm-pcm-dsp.1", + .dynamic = 1, + .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, + .dpcm_playback = 1, + .dpcm_capture = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA1, + .ops = &apq8096_ll_ops, + }, + { + .name = "MSM8996 Media2", + .stream_name = "MultiMedia2", + .cpu_dai_name = "MultiMedia2", + .platform_name = "msm-pcm-dsp.1", + .dynamic = 1, + .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, + .dpcm_playback = 1, + .dpcm_capture = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA2, + .ops = &apq8096_ll_ops, + }, + { + .name = "MSM8996 Media3", + .stream_name = "MultiMedia3", + .cpu_dai_name = "MultiMedia3", + .platform_name = "msm-pcm-dsp.1", + .dynamic = 1, + .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, + .dpcm_playback = 1, + .dpcm_capture = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA3, + .ops = &apq8096_ll_ops, + }, + { + .name = "MSM8996 Media5", + .stream_name = "MultiMedia5", + .cpu_dai_name = "MultiMedia5", + .platform_name = "msm-pcm-dsp.1", + .dynamic = 1, + .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, + .dpcm_playback = 1, + .dpcm_capture = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA5, + .ops = &apq8096_ll_ops, + }, + { + .name = "MSM8996 Media6", + .stream_name = "MultiMedia6", + .cpu_dai_name = "MultiMedia6", + .platform_name = "msm-pcm-dsp.1", + .dynamic = 1, + .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, + .dpcm_playback = 1, + .dpcm_capture = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA6, + .ops = &apq8096_ll_ops, + }, + { + .name = "MSM8996 Media8", + .stream_name = "MultiMedia8", + .cpu_dai_name = "MultiMedia8", + .platform_name = "msm-pcm-dsp.1", + .dynamic = 1, + .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, + .dpcm_playback = 1, + .dpcm_capture = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA8, + .ops = &apq8096_ll_ops, + }, + { + .name = "MSM8996 Media9", + .stream_name = "MultiMedia9", + .cpu_dai_name = "MultiMedia9", + .platform_name = "msm-pcm-dsp.1", + .dynamic = 1, + .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, + .dpcm_playback = 1, + .dpcm_capture = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .be_id = MSM_FRONTEND_DAI_MULTIMEDIA9, + .ops = &apq8096_ll_ops, + }, +}; + static struct snd_soc_dai_link apq8096_common_be_dai_links[] = { /* Backend AFE DAI Links */ { @@ -4115,6 +4311,13 @@ static struct snd_soc_dai_link apq8096_auto_dai_links[ ARRAY_SIZE(apq8096_auto_be_dai_links) + ARRAY_SIZE(apq8096_hdmi_dai_link)]; +static struct snd_soc_dai_link apq8096_auto_custom_dai_links[ + ARRAY_SIZE(apq8096_custom_fe_dai_links) + + ARRAY_SIZE(apq8096_auto_fe_dai_links) + + ARRAY_SIZE(apq8096_common_be_dai_links) + + ARRAY_SIZE(apq8096_auto_be_dai_links) + + ARRAY_SIZE(apq8096_hdmi_dai_link)]; + struct snd_soc_card snd_soc_card_auto_apq8096 = { .name = "apq8096-auto-snd-card", }; @@ -4127,6 +4330,10 @@ struct snd_soc_card snd_soc_card_adp_mmxf_apq8096 = { .name = "apq8096-adp-mmxf-snd-card", }; +struct snd_soc_card snd_soc_card_auto_custom_apq8096 = { + .name = "apq8096-auto-custom-snd-card", +}; + static int apq8096_populate_dai_link_component_of_node( struct snd_soc_card *card) { @@ -4220,6 +4427,8 @@ static const struct of_device_id apq8096_asoc_machine_of_match[] = { .data = "adp_agave_codec"}, { .compatible = "qcom,apq8096-asoc-snd-adp-mmxf", .data = "adp_mmxf_codec"}, + { .compatible = "qcom,apq8096-asoc-snd-auto-custom", + .data = "auto_custom_codec"}, {}, }; @@ -4243,31 +4452,55 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) card = &snd_soc_card_adp_agave_apq8096; else if (!strcmp(match->data, "adp_mmxf_codec")) card = &snd_soc_card_adp_mmxf_apq8096; - else { + else if (!strcmp(match->data, "auto_custom_codec")) { + card = &snd_soc_card_auto_custom_apq8096; + } else { dev_err(dev, "%s: Codec not supported\n", __func__); return NULL; } - /* same FE and BE used for all codec */ - len_1 = ARRAY_SIZE(apq8096_common_dai_links); - len_2 = len_1 + ARRAY_SIZE(apq8096_auto_fe_dai_links); - len_3 = len_2 + ARRAY_SIZE(apq8096_common_be_dai_links); + if (!strcmp(match->data, "auto_custom_codec")) { + len_1 = ARRAY_SIZE(apq8096_custom_fe_dai_links); + len_2 = len_1 + ARRAY_SIZE(apq8096_auto_fe_dai_links); + len_3 = len_2 + ARRAY_SIZE(apq8096_common_be_dai_links); - memcpy(apq8096_auto_dai_links, - apq8096_common_dai_links, - sizeof(apq8096_common_dai_links)); - memcpy(apq8096_auto_dai_links + len_1, - apq8096_auto_fe_dai_links, - sizeof(apq8096_auto_fe_dai_links)); - memcpy(apq8096_auto_dai_links + len_2, - apq8096_common_be_dai_links, - sizeof(apq8096_common_be_dai_links)); - memcpy(apq8096_auto_dai_links + len_3, - apq8096_auto_be_dai_links, - sizeof(apq8096_auto_be_dai_links)); + memcpy(apq8096_auto_custom_dai_links, + apq8096_custom_fe_dai_links, + sizeof(apq8096_custom_fe_dai_links)); + memcpy(apq8096_auto_custom_dai_links + len_1, + apq8096_auto_fe_dai_links, + sizeof(apq8096_auto_fe_dai_links)); + memcpy(apq8096_auto_custom_dai_links + len_2, + apq8096_common_be_dai_links, + sizeof(apq8096_common_be_dai_links)); + memcpy(apq8096_auto_custom_dai_links + len_3, + apq8096_auto_be_dai_links, + sizeof(apq8096_auto_be_dai_links)); + + dailink = apq8096_auto_custom_dai_links; + } else { + /* same FE and BE used for all non-custom codec */ + len_1 = ARRAY_SIZE(apq8096_common_dai_links); + len_2 = len_1 + ARRAY_SIZE(apq8096_auto_fe_dai_links); + len_3 = len_2 + ARRAY_SIZE(apq8096_common_be_dai_links); + + memcpy(apq8096_auto_dai_links, + apq8096_common_dai_links, + sizeof(apq8096_common_dai_links)); + memcpy(apq8096_auto_dai_links + len_1, + apq8096_auto_fe_dai_links, + sizeof(apq8096_auto_fe_dai_links)); + memcpy(apq8096_auto_dai_links + len_2, + apq8096_common_be_dai_links, + sizeof(apq8096_common_be_dai_links)); + memcpy(apq8096_auto_dai_links + len_3, + apq8096_auto_be_dai_links, + sizeof(apq8096_auto_be_dai_links)); + + dailink = apq8096_auto_dai_links; + } - dailink = apq8096_auto_dai_links; len_4 = len_3 + ARRAY_SIZE(apq8096_auto_be_dai_links); if (of_property_read_bool(dev->of_node, "qcom,hdmi-audio-rx")) { @@ -4308,10 +4541,20 @@ static int apq8096_init_tdm_dev(struct device *dev) memcpy(tdm_slot_offset, tdm_slot_offset_adp_mmxf, sizeof(tdm_slot_offset_adp_mmxf)); + } else if (!strcmp(match->data, "auto_custom_codec")) { + dev_dbg(dev, "%s: custom tdm slot offset\n", __func__); + msm_tdm_slot_width = 16; + msm_tdm_num_slots = 16; + memcpy(tdm_slot_offset, + tdm_slot_offset_custom, + sizeof(tdm_slot_offset_custom)); } else { dev_dbg(dev, "%s: DEFAULT tdm slot offset\n", __func__); } + dev_dbg(dev, "%s: tdm slot_width %d, num_slots %d\n", + __func__, msm_tdm_slot_width, msm_tdm_num_slots); + return 0; }