asoc: Update machine driver for kona

-Update machine driver on kernel-5.4 for kona.
-update and affine qos value.
-update wsa component init function.
-update rx_tx codec init function.
-remove msm_init_aux_dev function.

Change-Id: Id0934adcd0e41968d9f9f3c8341525f3a7152858
This commit is contained in:
Dechen Chai 2022-04-11 12:13:09 +05:30
commit f6bee9a0da
2 changed files with 329 additions and 549 deletions

View file

@ -15,6 +15,9 @@ endif
ifeq ($(TARGET_SUPPORT), qrbx210)
KBUILD_OPTIONS += CONFIG_ARCH_BENGAL=y
endif
ifeq ($(TARGET_SUPPORT), qrb5165)
KBUILD_OPTIONS += CONFIG_ARCH_KONA=y
endif
subdir-ccflags-y += -I$(AUDIO_ROOT)/include/uapi/
@ -39,6 +42,12 @@ obj-m += asoc/codecs/bolero/
obj-m += asoc/codecs/wcd937x/
KBUILD_CFLAGS += -Wno-error
endif
ifeq ($(TARGET_SUPPORT), $(filter $(TARGET_SUPPORT), qrb5165))
obj-m += asoc/codecs/bolero/
obj-m += asoc/codecs/wcd938x/
bj-m += asoc/codecs/wsa883x/
KBUILD_CFLAGS += -Wno-error
endif
ifeq ($(TARGET_SUPPORT), sdmsteppe)
obj-m += asoc/codecs/bolero/
obj-m += asoc/codecs/wcd937x/

View file

@ -198,6 +198,8 @@ struct msm_asoc_mach_data {
struct clk *lpass_audio_hw_vote;
int core_audio_vote_count;
u32 tdm_max_slots; /* Max TDM slots used */
int wcd_disabled;
u32 wsa_max_devs;
};
struct tdm_port {
@ -905,6 +907,9 @@ static int dmic_4_5_gpio_cnt;
static void *def_wcd_mbhc_cal(void);
static int msm_rx_tx_codec_init(struct snd_soc_pcm_runtime*);
static int msm_int_wsa_init(struct snd_soc_pcm_runtime*);
/*
* Need to report LINEIN
* if R/L channel impedance is larger than 5K ohm
@ -932,6 +937,68 @@ static struct wcd_mbhc_config wcd_mbhc_cfg = {
.moisture_duty_cycle_en = true,
};
/* set audio task affinity to core 1 & 2 */
static const unsigned int audio_core_list[] = {1, 2};
static cpumask_t audio_cpu_map = CPU_MASK_NONE;
static struct dev_pm_qos_request *msm_audio_req;
static unsigned int qos_client_active_cnt;
static void msm_audio_add_qos_request(void)
{
int i;
int cpu = 0;
msm_audio_req = kcalloc(num_possible_cpus(),
sizeof(struct dev_pm_qos_request), GFP_KERNEL);
if (!msm_audio_req)
return;
for (i = 0; i < ARRAY_SIZE(audio_core_list); i++) {
if (audio_core_list[i] >= num_possible_cpus())
pr_err("%s incorrect cpu id: %d specified.\n",
__func__, audio_core_list[i]);
else
cpumask_set_cpu(audio_core_list[i], &audio_cpu_map);
}
for_each_cpu(cpu, &audio_cpu_map) {
dev_pm_qos_add_request(get_cpu_device(cpu),
&msm_audio_req[cpu],
DEV_PM_QOS_RESUME_LATENCY,
PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE);
pr_debug("%s set cpu affinity to core %d.\n", __func__, cpu);
}
}
static void msm_audio_remove_qos_request(void)
{
int cpu = 0;
if (msm_audio_req) {
for_each_cpu(cpu, &audio_cpu_map) {
dev_pm_qos_remove_request(
&msm_audio_req[cpu]);
pr_debug("%s remove cpu affinity of core %d.\n",
__func__, cpu);
}
kfree(msm_audio_req);
}
}
static void msm_audio_update_qos_request(u32 latency)
{
int cpu = 0;
if (msm_audio_req) {
for_each_cpu(cpu, &audio_cpu_map) {
dev_pm_qos_update_request(
&msm_audio_req[cpu], latency);
pr_debug("%s update latency of core %d to %ul.\n",
__func__, cpu, latency);
}
}
}
static inline int param_is_mask(int p)
{
return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
@ -4990,24 +5057,26 @@ err:
static int msm_fe_qos_prepare(struct snd_pcm_substream *substream)
{
cpumask_t mask;
if (pm_qos_request_active(&substream->latency_pm_qos_req))
pm_qos_remove_request(&substream->latency_pm_qos_req);
cpumask_clear(&mask);
cpumask_set_cpu(1, &mask); /* affine to core 1 */
cpumask_set_cpu(2, &mask); /* affine to core 2 */
cpumask_copy(&substream->latency_pm_qos_req.cpus_affine, &mask);
qos_client_active_cnt++;
if (qos_client_active_cnt == 1)
msm_audio_update_qos_request(MSM_LL_QOS_VALUE);
substream->latency_pm_qos_req.type = PM_QOS_REQ_AFFINE_CORES;
pm_qos_add_request(&substream->latency_pm_qos_req,
PM_QOS_CPU_DMA_LATENCY,
MSM_LL_QOS_VALUE);
return 0;
}
static void msm_fe_qos_shutdown(struct snd_pcm_substream *substream)
{
(void)substream;
if (qos_client_active_cnt > 0)
qos_client_active_cnt--;
if (qos_client_active_cnt == 0)
msm_audio_update_qos_request(PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE);
}
void mi2s_disable_audio_vote(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
@ -5275,6 +5344,7 @@ static struct snd_soc_ops msm_mi2s_be_ops = {
static struct snd_soc_ops msm_fe_qos_ops = {
.prepare = msm_fe_qos_prepare,
.shutdown = msm_fe_qos_shutdown,
};
static struct snd_soc_ops msm_cdc_dma_be_ops = {
@ -5466,17 +5536,86 @@ static void msm_add_auxpcm_snd_controls(struct snd_soc_component *component)
}
#endif
static int msm_int_audrx_init(struct snd_soc_pcm_runtime *rtd)
static int msm_int_wsa_init(struct snd_soc_pcm_runtime *rtd)
{
u8 spkleft_ports[WSA881X_MAX_SWR_PORTS] = {0, 1, 2, 3};
u8 spkright_ports[WSA881X_MAX_SWR_PORTS] = {0, 1, 2, 3};
u8 spkleft_port_types[WSA881X_MAX_SWR_PORTS] = {SPKR_L, SPKR_L_COMP,
SPKR_L_BOOST, SPKR_L_VI};
u8 spkright_port_types[WSA881X_MAX_SWR_PORTS] = {SPKR_R, SPKR_R_COMP,
SPKR_R_BOOST, SPKR_R_VI};
unsigned int ch_rate[WSA881X_MAX_SWR_PORTS] = {2400, 600, 300, 1200};
unsigned int ch_mask[WSA881X_MAX_SWR_PORTS] = {0x1, 0xF, 0x3, 0x3};
struct snd_soc_component *component = NULL;
struct snd_soc_dapm_context *dapm = NULL;
struct msm_asoc_mach_data *pdata =
snd_soc_card_get_drvdata(rtd->card);
int wsa_active_devs = 0;
if (pdata->wsa_max_devs > 0) {
component = snd_soc_rtdcom_lookup(rtd, "wsa-codec.1");
if (component) {
dapm = snd_soc_component_get_dapm(component);
wsa881x_set_channel_map(component, &spkleft_ports[0],
WSA883X_MAX_SWR_PORTS, &ch_mask[0],
&ch_rate[0], &spkleft_port_types[0]);
if (dapm->component) {
snd_soc_dapm_ignore_suspend(dapm, "SpkrLeft IN");
snd_soc_dapm_ignore_suspend(dapm, "SpkrLeft SPKR");
}
/*
* Send speaker configuration only for WSA8810.
* Default configuration is for WSA8815.
*/
wsa_macro_set_spkr_mode(component,WSA_MACRO_SPKR_MODE_1);
wsa_macro_set_spkr_gain_offset(component,WSA_MACRO_GAIN_OFFSET_M1P5_DB);
wsa881x_codec_info_create_codec_entry(pdata->codec_root,
component);
wsa_active_devs++;
} else {
pr_info("%s: wsa-codec.1 component is NULL\n", __func__);
}
}
/* If current platform has more than one WSA */
if (pdata->wsa_max_devs > wsa_active_devs) {
component = snd_soc_rtdcom_lookup(rtd, "wsa-codec.2");
if (!component) {
pr_err("%s: wsa-codec.2 component is NULL\n", __func__);
pr_err("%s: %d WSA is found. Expect %d WSA.",
__func__, wsa_active_devs, pdata->wsa_max_devs);
return -EINVAL;
}
dapm = snd_soc_component_get_dapm(component);
wsa881x_set_channel_map(component, &spkright_ports[0],
WSA883X_MAX_SWR_PORTS, &ch_mask[0],
&ch_rate[0], &spkright_port_types[0]);
if (dapm->component) {
snd_soc_dapm_ignore_suspend(dapm, "SpkrRight IN");
snd_soc_dapm_ignore_suspend(dapm, "SpkrRight SPKR");
}
wsa881x_codec_info_create_codec_entry(pdata->codec_root,
component);
}
return 0;
}
static int msm_rx_tx_codec_init(struct snd_soc_pcm_runtime *rtd)
{
int ret = -EINVAL;
struct snd_soc_component *component;
struct snd_soc_dapm_context *dapm;
struct snd_card *card;
struct snd_soc_component *component = NULL;
struct snd_soc_component *bolero_component = NULL;
struct snd_soc_dapm_context *dapm = NULL;
struct snd_card *card = NULL;
struct snd_info_entry *entry;
struct snd_soc_component *aux_comp;
struct platform_device *pdev = NULL;
int i = 0;
bool is_wcd937x_used = false;
int codec_variant = -1;
char *data = NULL;
struct msm_asoc_mach_data *pdata =
snd_soc_card_get_drvdata(rtd->card);
@ -5486,6 +5625,8 @@ static int msm_int_audrx_init(struct snd_soc_pcm_runtime *rtd)
pr_err("%s: could not find component for bolero_codec\n",
__func__);
return ret;
} else {
bolero_component = component;
}
dapm = snd_soc_component_get_dapm(component);
@ -5534,87 +5675,104 @@ static int msm_int_audrx_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_sync(dapm);
/*
* Send speaker configuration only for WSA8810.
* Default configuration is for WSA8815.
*/
dev_dbg(component->dev, "%s: Number of aux devices: %d\n",
__func__, rtd->card->num_aux_devs);
if (rtd->card->num_aux_devs &&
!list_empty(&rtd->card->component_dev_list)) {
list_for_each_entry(aux_comp,
&rtd->card->aux_comp_list,
card_aux_list) {
if (aux_comp->name != NULL && (
!strcmp(aux_comp->name, WSA8810_NAME_1) ||
!strcmp(aux_comp->name, WSA8810_NAME_2))) {
wsa_macro_set_spkr_mode(component,
WSA_MACRO_SPKR_MODE_1);
wsa_macro_set_spkr_gain_offset(component,
WSA_MACRO_GAIN_OFFSET_M1P5_DB);
} else if (aux_comp->name != NULL && (
!strcmp(aux_comp->name, WSA8815_NAME_1) ||
!strcmp(aux_comp->name, WSA8815_NAME_2))) {
wsa_macro_set_spkr_mode(component,
WSA_MACRO_SPKR_MODE_DEFAULT);
}
}
}
for (i = 0; i < rtd->card->num_aux_devs; i++)
{
if (msm_aux_dev[i].name != NULL ) {
if (strstr(msm_aux_dev[i].name, "wsa"))
continue;
}
if (msm_aux_dev[i].codec_of_node) {
pdev = of_find_device_by_node(
msm_aux_dev[i].codec_of_node);
if (pdev)
data = (char*) of_device_get_match_data(
&pdev->dev);
if (data != NULL) {
if (!strncmp(data, "wcd937x",
sizeof("wcd937x"))) {
is_wcd937x_used = true;
break;
}
}
}
}
if (is_wcd937x_used) {
bolero_set_port_map(component,
ARRAY_SIZE(sm_port_map_wcd937x),
sm_port_map_wcd937x);
} else if (pdata->lito_v2_enabled) {
/*
* Enable tx data line3 for saipan version v2 and
* write corresponding lpi register.
*/
bolero_set_port_map(component, ARRAY_SIZE(sm_port_map_v2),
sm_port_map_v2);
} else {
bolero_set_port_map(component, ARRAY_SIZE(sm_port_map),
sm_port_map);
}
card = rtd->card->snd_card;
if (!pdata->codec_root) {
entry = msm_snd_info_create_subdir(card->module, "codecs",
card->proc_root);
if (!entry) {
pr_debug("%s: Cannot create codecs module entry\n",
__func__);
ret = 0;
goto err;
return 0;
}
pdata->codec_root = entry;
}
bolero_info_create_codec_entry(pdata->codec_root, component);
bolero_register_wake_irq(component, false);
/*
* Send speaker configuration only for WSA8810.
* Default configuration is for WSA8815.
*/
component = snd_soc_rtdcom_lookup(rtd, "wsa-codec.1");
if (!component) {
component = snd_soc_rtdcom_lookup(rtd, "wsa-codec.3");
if (!component) {
pr_debug("%s: wsa-codec.3 component is NULL\n",
__func__);
} else {
wsa_macro_set_spkr_mode(bolero_component,WSA_MACRO_SPKR_MODE_DEFAULT);
}
} else {
wsa_macro_set_spkr_mode(bolero_component,WSA_MACRO_SPKR_MODE_1);
wsa_macro_set_spkr_gain_offset(bolero_component,WSA_MACRO_GAIN_OFFSET_M1P5_DB);
}
if (pdata->wcd_disabled) {
codec_reg_done = true;
return 0;
}
component = snd_soc_rtdcom_lookup(rtd, WCD938X_DRV_NAME);
if (!component) {
component = snd_soc_rtdcom_lookup(rtd, WCD937X_DRV_NAME);
if (!component) {
pr_err("%s component is NULL\n", __func__);
return -EINVAL;
}
}
dapm = snd_soc_component_get_dapm(component);
card = component->card->snd_card;
snd_soc_dapm_ignore_suspend(dapm, "EAR");
snd_soc_dapm_ignore_suspend(dapm, "AUX");
snd_soc_dapm_ignore_suspend(dapm, "HPHL");
snd_soc_dapm_ignore_suspend(dapm, "HPHR");
snd_soc_dapm_ignore_suspend(dapm, "AMIC1");
snd_soc_dapm_ignore_suspend(dapm, "AMIC2");
snd_soc_dapm_ignore_suspend(dapm, "AMIC3");
snd_soc_dapm_ignore_suspend(dapm, "AMIC4");
snd_soc_dapm_sync(dapm);
if (!strncmp(component->driver->name, "wcd937x", 7)) {
wcd937x_info_create_codec_entry(pdata->codec_root, component);
ret = snd_soc_add_component_controls(component,
msm_int_wcd937x_snd_controls,
ARRAY_SIZE(msm_int_wcd937x_snd_controls));
bolero_set_port_map(bolero_component,
ARRAY_SIZE(sm_port_map_wcd937x),
sm_port_map_wcd937x);
} else {
wcd938x_info_create_codec_entry(pdata->codec_root, component);
codec_variant = wcd938x_get_codec_variant(component);
dev_dbg(component->dev, "%s: variant %d\n", __func__, codec_variant);
if (codec_variant == WCD9380)
ret = snd_soc_add_component_controls(bolero_component,
msm_int_wcd9380_snd_controls,
ARRAY_SIZE(msm_int_wcd9380_snd_controls));
else if (codec_variant == WCD9385)
ret = snd_soc_add_component_controls(bolero_component,
msm_int_wcd9385_snd_controls,
ARRAY_SIZE(msm_int_wcd9385_snd_controls));
if (pdata->lito_v2_enabled) {
/*
* Enable tx data line3 for saipan version v2 and
* write corresponding lpi register.
*/
bolero_set_port_map(component, ARRAY_SIZE(sm_port_map_v2),
sm_port_map_v2);
} else {
bolero_set_port_map(component, ARRAY_SIZE(sm_port_map),
sm_port_map);
}
}
if (ret < 0) {
dev_err(component->dev, "%s: add codec specific snd controls failed: %d\n",
__func__, ret);
return ret;
}
codec_reg_done = true;
return 0;
err:
@ -6811,7 +6969,7 @@ static struct snd_soc_dai_link msm_wsa_cdc_dma_be_dai_links[] = {
.stream_name = "WSA CDC DMA0 Playback",
.no_pcm = 1,
.dpcm_playback = 1,
.init = &msm_int_audrx_init,
.init = &msm_int_wsa_init,
.id = MSM_BACKEND_DAI_WSA_CDC_DMA_RX_0,
.be_hw_params_fixup = msm_be_hw_params_fixup,
.ignore_pmdown_time = 1,
@ -6869,6 +7027,7 @@ static struct snd_soc_dai_link msm_rx_tx_cdc_dma_be_dai_links[] = {
.ignore_suspend = 1,
.ops = &msm_cdc_dma_be_ops,
SND_SOC_DAILINK_REG(rx_dma_rx0),
.init = &msm_rx_tx_codec_init,
},
{
.name = LPASS_BE_RX_CDC_DMA_RX_1,
@ -7181,6 +7340,62 @@ static const struct of_device_id kona_asoc_machine_of_match[] = {
{},
};
static int msm_snd_card_late_probe(struct snd_soc_card *card)
{
struct snd_soc_component *component = NULL;
const char *be_dl_name = LPASS_BE_RX_CDC_DMA_RX_0;
struct snd_soc_pcm_runtime *rtd;
struct msm_asoc_mach_data *pdata;
int ret = 0;
void *mbhc_calibration;
bool is_wcd937x = false;
pdata = snd_soc_card_get_drvdata(card);
if (!pdata)
return -EINVAL;
if (pdata->wcd_disabled)
return 0;
rtd = snd_soc_get_pcm_runtime(card, be_dl_name);
if (!rtd) {
dev_err(card->dev,
"%s: snd_soc_get_pcm_runtime for %s failed!\n",
__func__, be_dl_name);
return -EINVAL;
}
component = snd_soc_rtdcom_lookup(rtd, WCD938X_DRV_NAME);
if (!component) {
component = snd_soc_rtdcom_lookup(rtd, WCD937X_DRV_NAME);
if (!component) {
pr_err("%s component is NULL\n", __func__);
return -EINVAL;
} else {
is_wcd937x = true;
}
}
mbhc_calibration = def_wcd_mbhc_cal();
if (!mbhc_calibration)
return -ENOMEM;
wcd_mbhc_cfg.calibration = mbhc_calibration;
if (!is_wcd937x)
ret = wcd938x_mbhc_hs_detect(component, &wcd_mbhc_cfg);
else
ret = wcd937x_mbhc_hs_detect(component, &wcd_mbhc_cfg);
if (ret) {
dev_err(component->dev, "%s: mbhc hs detect failed, err:%d\n",
__func__, ret);
goto err_hs_detect;
}
return 0;
err_hs_detect:
kfree(mbhc_calibration);
return ret;
}
static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
{
struct snd_soc_card *card = NULL;
@ -7350,470 +7565,12 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
if (card) {
card->dai_link = dailink;
card->num_links = total_links;
card->late_probe = msm_snd_card_late_probe;
}
return card;
}
static int msm_wsa881x_init(struct snd_soc_component *component)
{
u8 spkleft_ports[WSA881X_MAX_SWR_PORTS] = {0, 1, 2, 3};
u8 spkright_ports[WSA881X_MAX_SWR_PORTS] = {0, 1, 2, 3};
u8 spkleft_port_types[WSA881X_MAX_SWR_PORTS] = {SPKR_L, SPKR_L_COMP,
SPKR_L_BOOST, SPKR_L_VI};
u8 spkright_port_types[WSA881X_MAX_SWR_PORTS] = {SPKR_R, SPKR_R_COMP,
SPKR_R_BOOST, SPKR_R_VI};
unsigned int ch_rate[WSA881X_MAX_SWR_PORTS] = {2400, 600, 300, 1200};
unsigned int ch_mask[WSA881X_MAX_SWR_PORTS] = {0x1, 0xF, 0x3, 0x3};
struct msm_asoc_mach_data *pdata;
struct snd_soc_dapm_context *dapm;
struct snd_card *card;
struct snd_info_entry *entry;
int ret = 0;
if (!component) {
pr_err("%s component is NULL\n", __func__);
return -EINVAL;
}
card = component->card->snd_card;
dapm = snd_soc_component_get_dapm(component);
if (!strcmp(component->name_prefix, "SpkrLeft")) {
dev_dbg(component->dev, "%s: setting left ch map to codec %s\n",
__func__, component->name);
if (strnstr(component->name, "wsa883x", sizeof(component->name)))
wsa883x_set_channel_map(component, &spkleft_ports[0],
WSA881X_MAX_SWR_PORTS, &ch_mask[0],
&ch_rate[0], &spkleft_port_types[0]);
else
wsa881x_set_channel_map(component, &spkleft_ports[0],
WSA881X_MAX_SWR_PORTS, &ch_mask[0],
&ch_rate[0], &spkleft_port_types[0]);
if (dapm->component) {
snd_soc_dapm_ignore_suspend(dapm, "SpkrLeft IN");
snd_soc_dapm_ignore_suspend(dapm, "SpkrLeft SPKR");
}
} else if (!strcmp(component->name_prefix, "SpkrRight")) {
dev_dbg(component->dev, "%s: setting right ch map to codec %s\n",
__func__, component->name);
if (strnstr(component->name, "wsa883x", sizeof(component->name)))
wsa883x_set_channel_map(component, &spkright_ports[0],
WSA881X_MAX_SWR_PORTS, &ch_mask[0],
&ch_rate[0], &spkright_port_types[0]);
else
wsa881x_set_channel_map(component, &spkright_ports[0],
WSA881X_MAX_SWR_PORTS, &ch_mask[0],
&ch_rate[0], &spkright_port_types[0]);
if (dapm->component) {
snd_soc_dapm_ignore_suspend(dapm, "SpkrRight IN");
snd_soc_dapm_ignore_suspend(dapm, "SpkrRight SPKR");
}
} else {
dev_err(component->dev, "%s: wrong codec name %s\n", __func__,
component->name);
ret = -EINVAL;
goto err;
}
pdata = snd_soc_card_get_drvdata(component->card);
if (!pdata->codec_root) {
entry = msm_snd_info_create_subdir(card->module, "codecs",
card->proc_root);
if (!entry) {
pr_err("%s: Cannot create codecs module entry\n",
__func__);
ret = 0;
goto err;
}
pdata->codec_root = entry;
}
if (strnstr(component->name, "wsa883x", sizeof(component->name)))
wsa883x_codec_info_create_codec_entry(pdata->codec_root,
component);
else
wsa881x_codec_info_create_codec_entry(pdata->codec_root,
component);
err:
return ret;
}
static int msm_aux_codec_init(struct snd_soc_component *component)
{
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
int ret = 0;
int codec_variant = -1;
void *mbhc_calibration;
struct snd_info_entry *entry;
struct snd_card *card = component->card->snd_card;
struct msm_asoc_mach_data *pdata;
snd_soc_dapm_ignore_suspend(dapm, "EAR");
snd_soc_dapm_ignore_suspend(dapm, "AUX");
snd_soc_dapm_ignore_suspend(dapm, "HPHL");
snd_soc_dapm_ignore_suspend(dapm, "HPHR");
snd_soc_dapm_ignore_suspend(dapm, "AMIC1");
snd_soc_dapm_ignore_suspend(dapm, "AMIC2");
snd_soc_dapm_ignore_suspend(dapm, "AMIC3");
snd_soc_dapm_ignore_suspend(dapm, "AMIC4");
snd_soc_dapm_sync(dapm);
pdata = snd_soc_card_get_drvdata(component->card);
if (!pdata->codec_root) {
entry = msm_snd_info_create_subdir(card->module, "codecs",
card->proc_root);
if (!entry) {
dev_dbg(component->dev, "%s: Cannot create codecs module entry\n",
__func__);
ret = 0;
goto mbhc_cfg_cal;
}
pdata->codec_root = entry;
}
if (!strncmp(component->driver->name, "wcd937x", 7)) {
wcd937x_info_create_codec_entry(pdata->codec_root, component);
ret = snd_soc_add_component_controls(component,
msm_int_wcd937x_snd_controls,
ARRAY_SIZE(msm_int_wcd937x_snd_controls));
} else {
wcd938x_info_create_codec_entry(pdata->codec_root, component);
codec_variant = wcd938x_get_codec_variant(component);
dev_dbg(component->dev, "%s: variant %d\n", __func__, codec_variant);
if (codec_variant == WCD9380)
ret = snd_soc_add_component_controls(component,
msm_int_wcd9380_snd_controls,
ARRAY_SIZE(msm_int_wcd9380_snd_controls));
else if (codec_variant == WCD9385)
ret = snd_soc_add_component_controls(component,
msm_int_wcd9385_snd_controls,
ARRAY_SIZE(msm_int_wcd9385_snd_controls));
}
if (ret < 0) {
dev_err(component->dev, "%s: add codec specific snd controls failed: %d\n",
__func__, ret);
return ret;
}
mbhc_cfg_cal:
mbhc_calibration = def_wcd_mbhc_cal();
if (!mbhc_calibration)
return -ENOMEM;
wcd_mbhc_cfg.calibration = mbhc_calibration;
if (!strncmp(component->driver->name, "wcd937x", 7))
ret = wcd937x_mbhc_hs_detect(component, &wcd_mbhc_cfg);
else
ret = wcd938x_mbhc_hs_detect(component, &wcd_mbhc_cfg);
if (ret) {
dev_err(component->dev, "%s: mbhc hs detect failed, err:%d\n",
__func__, ret);
goto err_hs_detect;
}
return 0;
err_hs_detect:
kfree(mbhc_calibration);
return ret;
}
static int msm_init_aux_dev(struct platform_device *pdev,
struct snd_soc_card *card)
{
struct device_node *wsa_of_node;
struct device_node *aux_codec_of_node;
u32 wsa_max_devs;
u32 wsa_dev_cnt;
u32 codec_max_aux_devs = 0;
u32 codec_aux_dev_cnt = 0;
int i;
struct msm_wsa881x_dev_info *wsa881x_dev_info;
struct aux_codec_dev_info *aux_cdc_dev_info;
struct snd_soc_dai_link_component *dlc;
const char *auxdev_name_prefix[1];
char *dev_name_str = NULL;
int found = 0;
int codecs_found = 0;
int ret = 0;
dlc = devm_kcalloc(&pdev->dev, 1,
sizeof(struct snd_soc_dai_link_component),
GFP_KERNEL);
/* Get maximum WSA device count for this platform */
ret = of_property_read_u32(pdev->dev.of_node,
"qcom,wsa-max-devs", &wsa_max_devs);
if (ret) {
dev_info(&pdev->dev,
"%s: wsa-max-devs property missing in DT %s, ret = %d\n",
__func__, pdev->dev.of_node->full_name, ret);
wsa_max_devs = 0;
goto codec_aux_dev;
}
if (wsa_max_devs == 0) {
dev_warn(&pdev->dev,
"%s: Max WSA devices is 0 for this target?\n",
__func__);
goto codec_aux_dev;
}
/* Get count of WSA device phandles for this platform */
wsa_dev_cnt = of_count_phandle_with_args(pdev->dev.of_node,
"qcom,wsa-devs", NULL);
if (wsa_dev_cnt == -ENOENT) {
dev_warn(&pdev->dev, "%s: No wsa device defined in DT.\n",
__func__);
goto err;
} else if (wsa_dev_cnt <= 0) {
dev_err(&pdev->dev,
"%s: Error reading wsa device from DT. wsa_dev_cnt = %d\n",
__func__, wsa_dev_cnt);
ret = -EINVAL;
goto err;
}
/*
* Expect total phandles count to be NOT less than maximum possible
* WSA count. However, if it is less, then assign same value to
* max count as well.
*/
if (wsa_dev_cnt < wsa_max_devs) {
dev_dbg(&pdev->dev,
"%s: wsa_max_devs = %d cannot exceed wsa_dev_cnt = %d\n",
__func__, wsa_max_devs, wsa_dev_cnt);
wsa_max_devs = wsa_dev_cnt;
}
/* Make sure prefix string passed for each WSA device */
ret = of_property_count_strings(pdev->dev.of_node,
"qcom,wsa-aux-dev-prefix");
if (ret != wsa_dev_cnt) {
dev_err(&pdev->dev,
"%s: expecting %d wsa prefix. Defined only %d in DT\n",
__func__, wsa_dev_cnt, ret);
ret = -EINVAL;
goto err;
}
/*
* Alloc mem to store phandle and index info of WSA device, if already
* registered with ALSA core
*/
wsa881x_dev_info = devm_kcalloc(&pdev->dev, wsa_max_devs,
sizeof(struct msm_wsa881x_dev_info),
GFP_KERNEL);
if (!wsa881x_dev_info) {
ret = -ENOMEM;
goto err;
}
/*
* search and check whether all WSA devices are already
* registered with ALSA core or not. If found a node, store
* the node and the index in a local array of struct for later
* use.
*/
for (i = 0; i < wsa_dev_cnt; i++) {
wsa_of_node = of_parse_phandle(pdev->dev.of_node,
"qcom,wsa-devs", i);
if (unlikely(!wsa_of_node)) {
/* we should not be here */
dev_err(&pdev->dev,
"%s: wsa dev node is not present\n",
__func__);
ret = -EINVAL;
goto err;
}
dlc->of_node = wsa_of_node;
dlc->name = NULL;
if (soc_find_component(dlc)) {
/* WSA device registered with ALSA core */
wsa881x_dev_info[found].of_node = wsa_of_node;
wsa881x_dev_info[found].index = i;
found++;
if (found == wsa_max_devs)
break;
}
}
if (found < wsa_max_devs) {
dev_dbg(&pdev->dev,
"%s: failed to find %d components. Found only %d\n",
__func__, wsa_max_devs, found);
return -EPROBE_DEFER;
}
dev_info(&pdev->dev,
"%s: found %d wsa881x devices registered with ALSA core\n",
__func__, found);
codec_aux_dev:
/* Get maximum aux codec device count for this platform */
ret = of_property_read_u32(pdev->dev.of_node,
"qcom,codec-max-aux-devs",
&codec_max_aux_devs);
if (ret) {
dev_err(&pdev->dev,
"%s: codec-max-aux-devs property missing in DT %s, ret = %d\n",
__func__, pdev->dev.of_node->full_name, ret);
codec_max_aux_devs = 0;
goto aux_dev_register;
}
if (codec_max_aux_devs == 0) {
dev_dbg(&pdev->dev,
"%s: Max aux codec devices is 0 for this target?\n",
__func__);
goto aux_dev_register;
}
/* Get count of aux codec device phandles for this platform */
codec_aux_dev_cnt = of_count_phandle_with_args(
pdev->dev.of_node,
"qcom,codec-aux-devs", NULL);
if (codec_aux_dev_cnt == -ENOENT) {
dev_warn(&pdev->dev, "%s: No aux codec defined in DT.\n",
__func__);
goto err;
} else if (codec_aux_dev_cnt <= 0) {
dev_err(&pdev->dev,
"%s: Error reading aux codec device from DT, dev_cnt=%d\n",
__func__, codec_aux_dev_cnt);
ret = -EINVAL;
goto err;
}
/*
* Expect total phandles count to be NOT less than maximum possible
* AUX device count. However, if it is less, then assign same value to
* max count as well.
*/
if (codec_aux_dev_cnt < codec_max_aux_devs) {
dev_dbg(&pdev->dev,
"%s: codec_max_aux_devs = %d cannot exceed codec_aux_dev_cnt = %d\n",
__func__, codec_max_aux_devs,
codec_aux_dev_cnt);
codec_max_aux_devs = codec_aux_dev_cnt;
}
/*
* Alloc mem to store phandle and index info of aux codec
* if already registered with ALSA core
*/
aux_cdc_dev_info = devm_kcalloc(&pdev->dev, codec_aux_dev_cnt,
sizeof(struct aux_codec_dev_info),
GFP_KERNEL);
if (!aux_cdc_dev_info) {
ret = -ENOMEM;
goto err;
}
/*
* search and check whether all aux codecs are already
* registered with ALSA core or not. If found a node, store
* the node and the index in a local array of struct for later
* use.
*/
for (i = 0; i < codec_aux_dev_cnt; i++) {
aux_codec_of_node = of_parse_phandle(pdev->dev.of_node,
"qcom,codec-aux-devs", i);
if (unlikely(!aux_codec_of_node)) {
/* we should not be here */
dev_err(&pdev->dev,
"%s: aux codec dev node is not present\n",
__func__);
ret = -EINVAL;
goto err;
}
dlc->of_node = aux_codec_of_node;
dlc->name = NULL;
if (soc_find_component(dlc)) {
/* AUX codec registered with ALSA core */
aux_cdc_dev_info[codecs_found].of_node =
aux_codec_of_node;
aux_cdc_dev_info[codecs_found].index = i;
codecs_found++;
}
}
if (codecs_found < codec_aux_dev_cnt) {
dev_dbg(&pdev->dev,
"%s: failed to find %d components. Found only %d\n",
__func__, codec_aux_dev_cnt, codecs_found);
return -EPROBE_DEFER;
}
dev_info(&pdev->dev,
"%s: found %d AUX codecs registered with ALSA core\n",
__func__, codecs_found);
aux_dev_register:
card->num_aux_devs = wsa_max_devs + codec_aux_dev_cnt;
card->num_configs = wsa_max_devs + codec_aux_dev_cnt;
/* Alloc array of AUX devs struct */
msm_aux_dev = devm_kcalloc(&pdev->dev, card->num_aux_devs,
sizeof(struct snd_soc_aux_dev),
GFP_KERNEL);
if (!msm_aux_dev) {
ret = -ENOMEM;
goto err;
}
/* Alloc array of codec conf struct */
msm_codec_conf = devm_kcalloc(&pdev->dev, card->num_configs,
sizeof(struct snd_soc_codec_conf),
GFP_KERNEL);
if (!msm_codec_conf) {
ret = -ENOMEM;
goto err;
}
for (i = 0; i < wsa_max_devs; i++) {
dev_name_str = devm_kzalloc(&pdev->dev, DEV_NAME_STR_LEN,
GFP_KERNEL);
if (!dev_name_str) {
ret = -ENOMEM;
goto err;
}
ret = of_property_read_string_index(pdev->dev.of_node,
"qcom,wsa-aux-dev-prefix",
wsa881x_dev_info[i].index,
auxdev_name_prefix);
if (ret) {
dev_err(&pdev->dev,
"%s: failed to read wsa aux dev prefix, ret = %d\n",
__func__, ret);
ret = -EINVAL;
goto err;
}
snprintf(dev_name_str, strlen("wsa881x.%d"), "wsa881x.%d", i);
msm_aux_dev[i].dlc.name = dev_name_str;
msm_aux_dev[i].dlc.dai_name = NULL;
msm_aux_dev[i].dlc.of_node =
wsa881x_dev_info[i].of_node;
msm_aux_dev[i].init = msm_wsa881x_init;
msm_codec_conf[i].dev_name = NULL;
msm_codec_conf[i].name_prefix = auxdev_name_prefix[0];
msm_codec_conf[i].of_node =
wsa881x_dev_info[i].of_node;
}
for (i = 0; i < codec_aux_dev_cnt; i++) {
msm_aux_dev[wsa_max_devs + i].dlc.name = NULL;
msm_aux_dev[wsa_max_devs + i].dlc.dai_name = NULL;
msm_aux_dev[wsa_max_devs + i].dlc.of_node =
aux_cdc_dev_info[i].of_node;
msm_aux_dev[wsa_max_devs + i].init = msm_aux_codec_init;
msm_codec_conf[wsa_max_devs + i].dev_name = NULL;
msm_codec_conf[wsa_max_devs + i].name_prefix =
NULL;
msm_codec_conf[wsa_max_devs + i].of_node =
aux_cdc_dev_info[i].of_node;
}
card->codec_conf = msm_codec_conf;
card->aux_dev = msm_aux_dev;
err:
return ret;
}
static void msm_i2s_auxpcm_init(struct platform_device *pdev)
{
int count = 0;
@ -7954,6 +7711,10 @@ static int msm_asoc_machine_probe(struct platform_device *pdev)
"qcom,lito-is-v2-enabled",
&pdata->lito_v2_enabled);
of_property_read_u32(pdev->dev.of_node,
"qcom,wcd-disabled",
&pdata->wcd_disabled);
card = populate_snd_card_dailinks(&pdev->dev);
if (!card) {
dev_err(&pdev->dev, "%s: Card uninitialized\n", __func__);
@ -7985,9 +7746,15 @@ static int msm_asoc_machine_probe(struct platform_device *pdev)
goto err;
}
ret = msm_init_aux_dev(pdev, card);
if (ret)
goto err;
/* Get maximum WSA device count for this platform */
ret = of_property_read_u32(pdev->dev.of_node,
"qcom,wsa-max-devs", &pdata->wsa_max_devs);
if (ret) {
dev_info(&pdev->dev,
"%s: wsa-max-devs property missing in DT %s, ret = %d\n",
__func__, pdev->dev.of_node->full_name, ret);
pdata->wsa_max_devs = 0;
}
ret = devm_snd_soc_register_card(&pdev->dev, card);
if (ret == -EPROBE_DEFER) {
@ -8132,6 +7899,9 @@ static int msm_asoc_machine_probe(struct platform_device *pdev)
is_initial_boot = true;
/* Add QoS request for audio tasks */
msm_audio_add_qos_request();
return 0;
err:
devm_kfree(&pdev->dev, pdata);
@ -8145,6 +7915,7 @@ static int msm_asoc_machine_remove(struct platform_device *pdev)
snd_event_master_deregister(&pdev->dev);
snd_soc_unregister_card(card);
msm_i2s_auxpcm_deinit();
msm_audio_remove_qos_request();
return 0;
}