2018-08-01 14:31:08 +05:30
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2018, Linaro Limited.
// Copyright (c) 2018, The Linux Foundation. All rights reserved.
# include <linux/module.h>
# include "common.h"
int qcom_snd_parse_of ( struct snd_soc_card * card )
{
struct device_node * np ;
struct device_node * codec = NULL ;
struct device_node * platform = NULL ;
struct device_node * cpu = NULL ;
struct device * dev = card - > dev ;
struct snd_soc_dai_link * link ;
2018-11-08 19:11:40 +05:30
struct of_phandle_args args ;
2019-06-06 13:16:58 +09:00
struct snd_soc_dai_link_component * dlc ;
2018-08-01 14:31:08 +05:30
int ret , num_links ;
ret = snd_soc_of_parse_card_name ( card , " model " ) ;
2020-07-23 20:39:02 +02:00
if ( ret = = 0 & & ! card - > name )
/* Deprecated, only for compatibility with old device trees */
ret = snd_soc_of_parse_card_name ( card , " qcom,model " ) ;
2018-08-01 14:31:08 +05:30
if ( ret ) {
dev_err ( dev , " Error parsing card name: %d \n " , ret ) ;
return ret ;
}
/* DAPM routes */
if ( of_property_read_bool ( dev - > of_node , " audio-routing " ) ) {
2020-07-23 20:39:02 +02:00
ret = snd_soc_of_parse_audio_routing ( card , " audio-routing " ) ;
if ( ret )
return ret ;
}
/* Deprecated, only for compatibility with old device trees */
if ( of_property_read_bool ( dev - > of_node , " qcom,audio-routing " ) ) {
ret = snd_soc_of_parse_audio_routing ( card , " qcom,audio-routing " ) ;
2018-08-01 14:31:08 +05:30
if ( ret )
return ret ;
}
/* Populate links */
num_links = of_get_child_count ( dev - > of_node ) ;
/* Allocate the DAI link array */
2020-07-23 20:38:58 +02:00
card - > dai_link = devm_kcalloc ( dev , num_links , sizeof ( * link ) , GFP_KERNEL ) ;
2018-08-01 14:31:08 +05:30
if ( ! card - > dai_link )
return - ENOMEM ;
card - > num_links = num_links ;
link = card - > dai_link ;
2019-06-06 13:16:58 +09:00
2018-08-01 14:31:08 +05:30
for_each_child_of_node ( dev - > of_node , np ) {
2019-06-17 22:28:13 -07:00
dlc = devm_kzalloc ( dev , 2 * sizeof ( * dlc ) , GFP_KERNEL ) ;
if ( ! dlc )
return - ENOMEM ;
2019-06-06 13:16:58 +09:00
2019-06-17 22:28:13 -07:00
link - > cpus = & dlc [ 0 ] ;
link - > platforms = & dlc [ 1 ] ;
2019-06-06 13:16:58 +09:00
2019-06-17 22:28:13 -07:00
link - > num_cpus = 1 ;
link - > num_platforms = 1 ;
2019-06-06 13:16:58 +09:00
2019-09-04 21:03:06 -07:00
ret = of_property_read_string ( np , " link-name " , & link - > name ) ;
if ( ret ) {
dev_err ( card - > dev , " error getting codec dai_link name \n " ) ;
goto err ;
}
2018-08-01 14:31:08 +05:30
cpu = of_get_child_by_name ( np , " cpu " ) ;
2019-02-19 16:46:51 +01:00
platform = of_get_child_by_name ( np , " platform " ) ;
codec = of_get_child_by_name ( np , " codec " ) ;
2018-08-01 14:31:08 +05:30
if ( ! cpu ) {
2019-09-04 21:03:06 -07:00
dev_err ( dev , " %s: Can't find cpu DT node \n " , link - > name ) ;
2018-08-01 14:31:08 +05:30
ret = - EINVAL ;
goto err ;
}
2018-11-08 19:11:40 +05:30
ret = of_parse_phandle_with_args ( cpu , " sound-dai " ,
" #sound-dai-cells " , 0 , & args ) ;
if ( ret ) {
2019-09-04 21:03:06 -07:00
dev_err ( card - > dev , " %s: error getting cpu phandle \n " , link - > name ) ;
2018-08-01 14:31:08 +05:30
goto err ;
}
2019-06-06 13:16:58 +09:00
link - > cpus - > of_node = args . np ;
2018-11-08 19:11:40 +05:30
link - > id = args . args [ 0 ] ;
2018-08-01 14:31:08 +05:30
2019-06-06 13:16:58 +09:00
ret = snd_soc_of_get_dai_name ( cpu , & link - > cpus - > dai_name ) ;
2018-08-01 14:31:08 +05:30
if ( ret ) {
2020-07-23 20:39:04 +02:00
if ( ret ! = - EPROBE_DEFER )
dev_err ( card - > dev , " %s: error getting cpu dai name: %d \n " ,
link - > name , ret ) ;
2018-08-01 14:31:08 +05:30
goto err ;
}
2020-07-23 20:39:01 +02:00
if ( platform ) {
2019-06-06 13:16:58 +09:00
link - > platforms - > of_node = of_parse_phandle ( platform ,
2018-08-01 14:31:08 +05:30
" sound-dai " ,
0 ) ;
2019-06-06 13:16:58 +09:00
if ( ! link - > platforms - > of_node ) {
2019-09-04 21:03:06 -07:00
dev_err ( card - > dev , " %s: platform dai not found \n " , link - > name ) ;
2018-08-01 14:31:08 +05:30
ret = - EINVAL ;
goto err ;
}
2020-07-23 20:39:01 +02:00
} else {
link - > platforms - > of_node = link - > cpus - > of_node ;
}
2018-08-01 14:31:08 +05:30
2020-07-23 20:39:01 +02:00
if ( codec ) {
2018-08-01 14:31:08 +05:30
ret = snd_soc_of_get_dai_link_codecs ( dev , codec , link ) ;
if ( ret < 0 ) {
2020-07-23 20:39:04 +02:00
if ( ret ! = - EPROBE_DEFER )
dev_err ( card - > dev , " %s: codec dai not found: %d \n " ,
link - > name , ret ) ;
2018-08-01 14:31:08 +05:30
goto err ;
}
2020-07-23 20:39:01 +02:00
if ( platform ) {
/* DPCM backend */
link - > no_pcm = 1 ;
link - > ignore_pmdown_time = 1 ;
}
2018-08-01 14:31:08 +05:30
} else {
2020-07-23 20:39:01 +02:00
/* DPCM frontend */
2019-06-06 13:16:58 +09:00
dlc = devm_kzalloc ( dev , sizeof ( * dlc ) , GFP_KERNEL ) ;
if ( ! dlc )
return - ENOMEM ;
link - > codecs = dlc ;
link - > num_codecs = 1 ;
link - > codecs - > dai_name = " snd-soc-dummy-dai " ;
link - > codecs - > name = " snd-soc-dummy " ;
2018-08-01 14:31:08 +05:30
link - > dynamic = 1 ;
}
2020-07-23 20:39:01 +02:00
if ( platform | | ! codec ) {
/* DPCM */
snd_soc_dai_link_set_capabilities ( link ) ;
link - > ignore_suspend = 1 ;
link - > nonatomic = 1 ;
}
2018-08-01 14:31:08 +05:30
link - > stream_name = link - > name ;
link + + ;
2019-02-19 16:46:51 +01:00
of_node_put ( cpu ) ;
of_node_put ( codec ) ;
of_node_put ( platform ) ;
2018-08-01 14:31:08 +05:30
}
return 0 ;
err :
2019-02-19 16:46:51 +01:00
of_node_put ( np ) ;
2018-08-01 14:31:08 +05:30
of_node_put ( cpu ) ;
of_node_put ( codec ) ;
of_node_put ( platform ) ;
return ret ;
}
EXPORT_SYMBOL ( qcom_snd_parse_of ) ;
MODULE_LICENSE ( " GPL v2 " ) ;