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 <honghaol@codeaurora.org>
This commit is contained in:
Honghao Liu 2017-03-08 16:36:35 -05:00 committed by Gerrit - the friendly Code Review server
parent 630218f710
commit f7d9f43f02
2 changed files with 270 additions and 25 deletions

View file

@ -2107,7 +2107,9 @@ Required properties:
"qcom,apq8096-asoc-snd-adp-agave" for adp agave codec and "qcom,apq8096-asoc-snd-adp-agave" for adp agave codec and
node is "sound-adp-agave", node is "sound-adp-agave",
"qcom,apq8096-asoc-snd-adp-mmxf" for adp mmxf codec and "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. - qcom,model : The user-visible name of this sound card.
- asoc-platform: This is phandle list containing the references to platform device - asoc-platform: This is phandle list containing the references to platform device
nodes that are used as part of the sound card dai-links. nodes that are used as part of the sound card dai-links.

View file

@ -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_bit_format = SNDRV_PCM_FORMAT_S16_LE;
static int msm_ec_ref_sampling_rate = SAMPLING_RATE_48KHZ; 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 void *adsp_state_notifier;
static bool dummy_device_registered; 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 */ {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", static char const *hdmi_rx_ch_text[] = {"Two", "Three", "Four", "Five",
"Six", "Seven", "Eight"}; "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 * use 32 bit slot width for max support of
* stream bit width. (slot_width > bit_width) * stream bit width. (slot_width > bit_width)
*/ */
slot_width = 32; slot_width = msm_tdm_slot_width;
break; break;
default: default:
pr_err("%s: invalid param format 0x%x\n", pr_err("%s: invalid param format 0x%x\n",
__func__, params_format(params)); __func__, params_format(params));
return -EINVAL; return -EINVAL;
} }
slots = 8; slots = msm_tdm_num_slots;
slot_mask = tdm_param_set_slot_mask(cpu_dai->id, slot_mask = tdm_param_set_slot_mask(cpu_dai->id,
slot_width, slots); slot_width, slots);
if (!slot_mask) { if (!slot_mask) {
@ -2660,7 +2719,7 @@ static int apq8096_get_ll_qos_val(struct snd_pcm_runtime *runtime)
return usecs; 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)) if (pm_qos_request_active(&substream->latency_pm_qos_req))
pm_qos_remove_request(&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; return 0;
} }
static struct snd_soc_ops apq8096_mm5_ops = { static struct snd_soc_ops apq8096_ll_ops = {
.prepare = apq8096_mm5_prepare, .prepare = apq8096_ll_prepare,
}; };
/* Digital audio interface glue - connects codec <---> CPU */ /* 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 */ /* this dainlink has playback support */
.ignore_pmdown_time = 1, .ignore_pmdown_time = 1,
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA5, .be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
.ops = &apq8096_mm5_ops, .ops = &apq8096_ll_ops,
}, },
{ {
.name = "Listen 1 Audio Service", .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[] = { static struct snd_soc_dai_link apq8096_common_be_dai_links[] = {
/* Backend AFE 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_auto_be_dai_links) +
ARRAY_SIZE(apq8096_hdmi_dai_link)]; 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 = { struct snd_soc_card snd_soc_card_auto_apq8096 = {
.name = "apq8096-auto-snd-card", .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", .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( static int apq8096_populate_dai_link_component_of_node(
struct snd_soc_card *card) struct snd_soc_card *card)
{ {
@ -4220,6 +4427,8 @@ static const struct of_device_id apq8096_asoc_machine_of_match[] = {
.data = "adp_agave_codec"}, .data = "adp_agave_codec"},
{ .compatible = "qcom,apq8096-asoc-snd-adp-mmxf", { .compatible = "qcom,apq8096-asoc-snd-adp-mmxf",
.data = "adp_mmxf_codec"}, .data = "adp_mmxf_codec"},
{ .compatible = "qcom,apq8096-asoc-snd-auto-custom",
.data = "auto_custom_codec"},
{}, {},
}; };
@ -4243,13 +4452,35 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
card = &snd_soc_card_adp_agave_apq8096; card = &snd_soc_card_adp_agave_apq8096;
else if (!strcmp(match->data, "adp_mmxf_codec")) else if (!strcmp(match->data, "adp_mmxf_codec"))
card = &snd_soc_card_adp_mmxf_apq8096; 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", dev_err(dev, "%s: Codec not supported\n",
__func__); __func__);
return NULL; return NULL;
} }
/* same FE and BE used for all codec */ 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_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_1 = ARRAY_SIZE(apq8096_common_dai_links);
len_2 = len_1 + ARRAY_SIZE(apq8096_auto_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); len_3 = len_2 + ARRAY_SIZE(apq8096_common_be_dai_links);
@ -4268,6 +4499,8 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
sizeof(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); len_4 = len_3 + ARRAY_SIZE(apq8096_auto_be_dai_links);
if (of_property_read_bool(dev->of_node, "qcom,hdmi-audio-rx")) { 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, memcpy(tdm_slot_offset,
tdm_slot_offset_adp_mmxf, tdm_slot_offset_adp_mmxf,
sizeof(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 { } else {
dev_dbg(dev, "%s: DEFAULT tdm slot offset\n", __func__); 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; return 0;
} }