diff --git a/asoc/kona.c b/asoc/kona.c index 498abb04cb..84d5c62a4c 100644 --- a/asoc/kona.c +++ b/asoc/kona.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -114,19 +115,6 @@ static struct wcd_mbhc_config wcd_mbhc_cfg = { .moisture_duty_cycle_en = true, }; -static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_dai_link *dai_link = rtd->dai_link; - int rc = 0; - - pr_debug("%s: dai_id= %d, format = %d, rate = %d\n", - __func__, dai_link->id, params_format(params), - params_rate(params)); - - return rc; -} - static bool msm_usbc_swap_gnd_mic(struct snd_soc_component *component, bool active) { struct snd_soc_card *card = component->card; @@ -371,6 +359,7 @@ static int msm_int_audrx_init(struct snd_soc_pcm_runtime *rtd) bolero_info_create_codec_entry(pdata->codec_root, component); bolero_register_wake_irq(component, false); codec_reg_done = true; + msm_common_dai_link_init(rtd); return 0; err: return ret; @@ -410,9 +399,15 @@ 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}; struct snd_soc_dai *codec_dai = rtd->codec_dai; + int ret = 0; - return snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch), + ret = snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch), tx_ch, ARRAY_SIZE(rx_ch), rx_ch); + if (ret) + return ret; + + msm_common_dai_link_init(rtd); + return ret; } static struct snd_soc_ops msm_common_be_ops = { @@ -434,7 +429,6 @@ static struct snd_soc_dai_link msm_common_dai_links[] = { .codec_name = "bolero_codec", .init = &msm_int_audrx_init, .ops = &msm_common_be_ops, - .be_hw_params_fixup = msm_be_hw_params_fixup, .ignore_suspend = 1, /* this dainlink has playback support */ .ignore_pmdown_time = 1, @@ -450,7 +444,6 @@ static struct snd_soc_dai_link msm_common_dai_links[] = { .codec_dai_name = "wsa_macro_rx_mix", .codec_name = "bolero_codec", .ops = &msm_common_be_ops, - .be_hw_params_fixup = msm_be_hw_params_fixup, .ignore_suspend = 1, /* this dainlink has playback support */ .ignore_pmdown_time = 1, @@ -466,10 +459,7 @@ static struct snd_soc_dai_link msm_common_dai_links[] = { .codec_dai_name = "wsa_macro_echo", .codec_name = "bolero_codec", .ops = &msm_common_be_ops, - .be_hw_params_fixup = msm_be_hw_params_fixup, .ignore_suspend = 1, - /* this dainlink has playback support */ - .ignore_pmdown_time = 1, }, { .name = LPASS_BE_RX_CDC_DMA_RX_0, @@ -482,7 +472,6 @@ static struct snd_soc_dai_link msm_common_dai_links[] = { .codec_dai_name = "rx_macro_rx1", .codec_name = "bolero_codec", .ops = &msm_common_be_ops, - .be_hw_params_fixup = msm_be_hw_params_fixup, .ignore_suspend = 1, /* this dainlink has playback support */ .ignore_pmdown_time = 1, @@ -498,7 +487,6 @@ static struct snd_soc_dai_link msm_common_dai_links[] = { .codec_dai_name = "rx_macro_rx2", .codec_name = "bolero_codec", .ops = &msm_common_be_ops, - .be_hw_params_fixup = msm_be_hw_params_fixup, .ignore_suspend = 1, /* this dainlink has playback support */ .ignore_pmdown_time = 1, @@ -514,7 +502,6 @@ static struct snd_soc_dai_link msm_common_dai_links[] = { .codec_dai_name = "rx_macro_rx3", .codec_name = "bolero_codec", .ops = &msm_common_be_ops, - .be_hw_params_fixup = msm_be_hw_params_fixup, .ignore_suspend = 1, /* this dainlink has playback support */ .ignore_pmdown_time = 1, @@ -530,7 +517,6 @@ static struct snd_soc_dai_link msm_common_dai_links[] = { .codec_dai_name = "rx_macro_rx4", .codec_name = "bolero_codec", .ops = &msm_common_be_ops, - .be_hw_params_fixup = msm_be_hw_params_fixup, .ignore_suspend = 1, /* this dainlink has playback support */ .ignore_pmdown_time = 1, @@ -546,10 +532,7 @@ static struct snd_soc_dai_link msm_common_dai_links[] = { .codec_dai_name = "tx_macro_tx1", .codec_name = "bolero_codec", .ops = &msm_common_be_ops, - .be_hw_params_fixup = msm_be_hw_params_fixup, .ignore_suspend = 1, - /* this dainlink has playback support */ - .ignore_pmdown_time = 1, }, { .name = LPASS_BE_TX_CDC_DMA_TX_4, @@ -562,10 +545,7 @@ static struct snd_soc_dai_link msm_common_dai_links[] = { .codec_dai_name = "tx_macro_tx2", .codec_name = "bolero_codec", .ops = &msm_common_be_ops, - .be_hw_params_fixup = msm_be_hw_params_fixup, .ignore_suspend = 1, - /* this dainlink has playback support */ - .ignore_pmdown_time = 1, }, { .name = LPASS_BE_VA_CDC_DMA_TX_0, @@ -578,10 +558,7 @@ static struct snd_soc_dai_link msm_common_dai_links[] = { .codec_dai_name = "va_macro_tx1", .codec_name = "bolero_codec", .ops = &msm_common_be_ops, - .be_hw_params_fixup = msm_be_hw_params_fixup, .ignore_suspend = 1, - /* this dainlink has playback support */ - .ignore_pmdown_time = 1, }, { .name = LPASS_BE_VA_CDC_DMA_TX_1, @@ -594,10 +571,7 @@ static struct snd_soc_dai_link msm_common_dai_links[] = { .codec_dai_name = "va_macro_tx2", .codec_name = "bolero_codec", .ops = &msm_common_be_ops, - .be_hw_params_fixup = msm_be_hw_params_fixup, .ignore_suspend = 1, - /* this dainlink has playback support */ - .ignore_pmdown_time = 1, }, { .name = LPASS_BE_VA_CDC_DMA_TX_2, @@ -610,10 +584,7 @@ static struct snd_soc_dai_link msm_common_dai_links[] = { .codec_dai_name = "va_macro_tx3", .codec_name = "bolero_codec", .ops = &msm_common_be_ops, - .be_hw_params_fixup = msm_be_hw_params_fixup, .ignore_suspend = 1, - /* this dainlink has playback support */ - .ignore_pmdown_time = 1, }, { .name = LPASS_BE_SLIMBUS_7_RX, @@ -629,6 +600,7 @@ static struct snd_soc_dai_link msm_common_dai_links[] = { .ignore_suspend = 1, /* this dainlink has playback support */ .ignore_pmdown_time = 1, + .init = &msm_wcn_init, }, { .name = LPASS_BE_SLIMBUS_7_TX, @@ -642,8 +614,6 @@ static struct snd_soc_dai_link msm_common_dai_links[] = { .ops = &msm_common_be_ops, .codec_dai_name = "btfm_bt_sco_slim_tx", .ignore_suspend = 1, - .ignore_pmdown_time = 1, - .init = &msm_wcn_init, }, { .name = LPASS_BE_DISPLAY_PORT_RX, @@ -669,7 +639,6 @@ static struct snd_soc_dai_link msm_common_dai_links[] = { .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .ignore_pmdown_time = 1, .ignore_suspend = 1, .ops = &msm_common_be_ops, }, @@ -705,53 +674,8 @@ static int msm_populate_dai_link_component_of_node( } for (i = 0; i < card->num_links; i++) { - if (dai_link[i].platform_of_node && dai_link[i].cpu_of_node) - continue; - - /* populate platform_of_node for snd card dai links */ - if (dai_link[i].platform_name && - !dai_link[i].platform_of_node) { - index = of_property_match_string(cdev->of_node, - "asoc-platform-names", - dai_link[i].platform_name); - if (index < 0) { - dev_err(cdev, "%s: No match found for platform name: %s\n", - __func__, dai_link[i].platform_name); - ret = index; - goto err; - } - np = of_parse_phandle(cdev->of_node, "asoc-platform", - index); - if (!np) { - dev_err(cdev, "%s: retrieving phandle for platform %s, index %d failed\n", - __func__, dai_link[i].platform_name, - index); - ret = -ENODEV; - goto err; - } - dai_link[i].platform_of_node = np; - dai_link[i].platform_name = NULL; - } - - /* populate cpu_of_node for snd card dai links */ - if (dai_link[i].cpu_dai_name && !dai_link[i].cpu_of_node) { - index = of_property_match_string(cdev->of_node, - "asoc-cpu-names", - dai_link[i].cpu_dai_name); - if (index >= 0) { - np = of_parse_phandle(cdev->of_node, "asoc-cpu", - index); - if (!np) { - dev_err(cdev, "%s: retrieving phandle for cpu dai %s failed\n", - __func__, - dai_link[i].cpu_dai_name); - ret = -ENODEV; - goto err; - } - dai_link[i].cpu_of_node = np; - dai_link[i].cpu_dai_name = NULL; - } - } + if (dai_link[i].init == NULL) + dai_link[i].init = &msm_common_dai_link_init; /* populate codec_of_node for snd card dai links */ if (dai_link[i].codec_name && !dai_link[i].codec_of_node) { @@ -806,7 +730,6 @@ static struct snd_soc_dai_link msm_stub_be_dai_links[] = { .codec_dai_name = "msm-stub-rx", .dpcm_playback = 1, .init = &msm_audrx_stub_init, - .be_hw_params_fixup = msm_be_hw_params_fixup, .ignore_pmdown_time = 1, .ignore_suspend = 1, .ops = &msm_stub_be_ops, @@ -818,7 +741,6 @@ static struct snd_soc_dai_link msm_stub_be_dai_links[] = { .codec_name = "msm-stub-codec.1", .codec_dai_name = "msm-stub-tx", .dpcm_capture = 1, - .be_hw_params_fixup = msm_be_hw_params_fixup, .ignore_suspend = 1, .ops = &msm_stub_be_ops, }, diff --git a/asoc/msm_common.c b/asoc/msm_common.c index d9860d94f4..d79fcdd760 100644 --- a/asoc/msm_common.c +++ b/asoc/msm_common.c @@ -15,9 +15,14 @@ #include #include #include +#include +#include +#include #include #include #include +#include + #include "msm_common.h" #define to_asoc_mach_common_pdata(kobj) \ @@ -31,6 +36,19 @@ static struct attribute device_state_attr = { .mode = 0660, }; +#define MAX_PORT 20 +#define CODEC_CHMAP "Channel Map" + +enum backend_id { + SLIM = 1, + CODEC_DMA, +}; + +struct chmap_pdata { + int id; + struct snd_soc_dai *dai; +}; + #define MAX_USR_INPUT 10 static ssize_t aud_dev_sysfs_store(struct kobject *kobj, @@ -265,3 +283,177 @@ void msm_common_snd_deinit(struct msm_common_pdata *common_pdata) mutex_destroy(&common_pdata->lock[count]); } } + +int msm_channel_map_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = sizeof(uint32_t) * MAX_PORT; + + return 0; +} + +int msm_channel_map_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct chmap_pdata *kctl_pdata = + (struct chmap_pdata *)kcontrol->private_data; + struct snd_soc_dai *codec_dai = kctl_pdata->dai; + int backend_id = kctl_pdata->id; + uint32_t rx_ch[MAX_PORT], tx_ch[MAX_PORT]; + uint32_t rx_ch_cnt = 0, tx_ch_cnt = 0; + uint32_t *chmap_data = NULL; + int ret = 0, len = 0; + + if (kctl_pdata == NULL) { + pr_debug("%s: chmap_pdata is not initialized\n", __func__); + return -EINVAL; + } + + ret = snd_soc_dai_get_channel_map(codec_dai, + &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch); + if (ret || (tx_ch_cnt == 0 && rx_ch_cnt == 0)) { + pr_err("%s: get channel map failed for %d\n", + __func__, backend_id); + return ret; + } + switch (backend_id) { + case SLIM: { + uint32_t *chmap; + uint32_t ch_cnt, i; + + if (rx_ch_cnt) { + chmap = rx_ch; + ch_cnt = rx_ch_cnt; + } else { + chmap = tx_ch; + ch_cnt = tx_ch_cnt; + } + len = sizeof(uint32_t) * (ch_cnt + 1); + chmap_data = kzalloc(len, GFP_KERNEL); + if (!chmap_data) + return -ENOMEM; + + chmap_data[0] = ch_cnt; + for (i = 0; i < ch_cnt; i++) + chmap_data[i+1] = chmap[i]; + + memcpy(ucontrol->value.bytes.data, chmap_data, len); + break; + } + case CODEC_DMA: { + chmap_data = kzalloc(sizeof(uint32_t) * 2, GFP_KERNEL); + if (!chmap_data) + return -ENOMEM; + + if (rx_ch_cnt) { + chmap_data[0] = rx_ch_cnt; + chmap_data[1] = rx_ch[0]; + } else { + chmap_data[0] = tx_ch_cnt; + chmap_data[1] = tx_ch[0]; + } + memcpy(ucontrol->value.bytes.data, chmap_data, + sizeof(uint32_t) * 2); + break; + } + default: + pr_err("%s, Invalid backend %d\n", __func__, backend_id); + ret = -EINVAL; + break; + } + kfree(chmap_data); + + return ret; +} + +void msm_common_get_backend_name(const char *stream_name, char **backend_name) +{ + char arg[21] = {0}; + char value[61] = {0}; + + sscanf(stream_name, "%20[^-]-%60s", arg, value); + *backend_name = kzalloc(strlen(arg)+1, GFP_KERNEL); + if (!(*backend_name)) + return; + + strlcpy(*backend_name, arg, strlen(arg)+1); +} + +int msm_common_dai_link_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_component *component = NULL; + struct snd_soc_dai_link *dai_link = rtd->dai_link; + struct device *dev = rtd->card->dev; + + int ret = 0; + const char *mixer_ctl_name = CODEC_CHMAP; + char *mixer_str = NULL; + char *backend_name = NULL; + uint32_t ctl_len = 0; + struct chmap_pdata *pdata; + struct snd_kcontrol *kctl; + struct snd_kcontrol_new msm_common_channel_map[1] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "?", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = msm_channel_map_info, + .get = msm_channel_map_get, + .private_value = 0, + } + }; + + if (!codec_dai) { + pr_err("%s: failed to get codec dai", __func__); + return -EINVAL; + } + component = codec_dai->component; + + msm_common_get_backend_name(dai_link->stream_name, &backend_name); + if (!backend_name) { + pr_err("%s: failed to get backend name", __func__); + return -EINVAL; + } + + pdata = devm_kzalloc(dev, sizeof(struct chmap_pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + if ((!strncmp(backend_name, "SLIM", strlen("SLIM"))) || + (!strncmp(backend_name, "CODEC_DMA", strlen("CODEC_DMA")))) { + ctl_len = strlen(dai_link->stream_name) + 1 + + strlen(mixer_ctl_name) + 1; + mixer_str = kzalloc(ctl_len, GFP_KERNEL); + if (!mixer_str) + return -ENOMEM; + + snprintf(mixer_str, ctl_len, "%s %s", dai_link->stream_name, + mixer_ctl_name); + msm_common_channel_map[0].name = mixer_str; + msm_common_channel_map[0].private_value = 0; + pr_debug("Registering new mixer ctl %s\n", mixer_str); + ret = snd_soc_add_component_controls(component, + msm_common_channel_map, + ARRAY_SIZE(msm_common_channel_map)); + kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str); + if (!kctl) { + pr_err("failed to get kctl %s\n", mixer_str); + ret = -EINVAL; + goto free_mixer_str; + } + if (!strncmp(backend_name, "SLIM", strlen("SLIM"))) + pdata->id = SLIM; + else + pdata->id = CODEC_DMA; + + pdata->dai = codec_dai; + kctl->private_data = pdata; +free_mixer_str: + kfree(backend_name); + kfree(mixer_str); + } + + return ret; +} diff --git a/asoc/msm_common.h b/asoc/msm_common.h index 7a905c5a48..e0e05e811e 100644 --- a/asoc/msm_common.h +++ b/asoc/msm_common.h @@ -54,4 +54,6 @@ int msm_common_snd_init(struct platform_device *pdev, struct snd_soc_card *card); void msm_common_snd_deinit(struct msm_common_pdata *pdata); + +int msm_common_dai_link_init(struct snd_soc_pcm_runtime *rtd); #endif