@@ -245,6 +245,155 @@ static const struct snd_soc_dai_ops avs_dai_nonhda_be_ops = {
245245 .trigger = avs_dai_nonhda_be_trigger ,
246246};
247247
248+ static int avs_dai_hda_be_startup (struct snd_pcm_substream * substream , struct snd_soc_dai * dai )
249+ {
250+ return avs_dai_startup (substream , dai , false);
251+ }
252+
253+ static void avs_dai_hda_be_shutdown (struct snd_pcm_substream * substream , struct snd_soc_dai * dai )
254+ {
255+ return avs_dai_nonhda_be_shutdown (substream , dai );
256+ }
257+
258+ static int avs_dai_hda_be_hw_params (struct snd_pcm_substream * substream ,
259+ struct snd_pcm_hw_params * hw_params , struct snd_soc_dai * dai )
260+ {
261+ struct avs_dma_data * data ;
262+ struct hdac_ext_stream * link_stream ;
263+
264+ data = snd_soc_dai_get_dma_data (dai , substream );
265+ if (data -> path )
266+ return 0 ;
267+
268+ link_stream = substream -> runtime -> private_data ;
269+
270+ return avs_dai_be_hw_params (substream , hw_params , dai ,
271+ hdac_stream (link_stream )-> stream_tag - 1 );
272+ }
273+
274+ static int avs_dai_hda_be_hw_free (struct snd_pcm_substream * substream , struct snd_soc_dai * dai )
275+ {
276+ struct avs_dma_data * data ;
277+ struct snd_soc_pcm_runtime * rtd = snd_pcm_substream_chip (substream );
278+ struct hdac_ext_stream * link_stream ;
279+ struct hdac_ext_link * link ;
280+ struct hda_codec * codec ;
281+
282+ dev_dbg (dai -> dev , "%s: %s\n" , __func__ , dai -> name );
283+
284+ data = snd_soc_dai_get_dma_data (dai , substream );
285+ if (!data -> path )
286+ return 0 ;
287+
288+ link_stream = substream -> runtime -> private_data ;
289+ link_stream -> link_prepared = false;
290+ avs_path_free (data -> path );
291+ data -> path = NULL ;
292+
293+ /* clear link <-> stream mapping */
294+ codec = dev_to_hda_codec (asoc_rtd_to_codec (rtd , 0 )-> dev );
295+ link = snd_hdac_ext_bus_link_at (& codec -> bus -> core , codec -> core .addr );
296+ if (!link )
297+ return - EINVAL ;
298+
299+ if (substream -> stream == SNDRV_PCM_STREAM_PLAYBACK )
300+ snd_hdac_ext_link_clear_stream_id (link , hdac_stream (link_stream )-> stream_tag );
301+
302+ return 0 ;
303+ }
304+
305+ static int avs_dai_hda_be_prepare (struct snd_pcm_substream * substream , struct snd_soc_dai * dai )
306+ {
307+ struct snd_soc_pcm_runtime * rtd = snd_pcm_substream_chip (substream );
308+ struct snd_pcm_runtime * runtime = substream -> runtime ;
309+ struct hdac_ext_stream * link_stream = runtime -> private_data ;
310+ struct hdac_ext_link * link ;
311+ struct hda_codec * codec ;
312+ struct hdac_bus * bus ;
313+ unsigned int format_val ;
314+ int ret ;
315+
316+ if (link_stream -> link_prepared )
317+ return 0 ;
318+
319+ codec = dev_to_hda_codec (asoc_rtd_to_codec (rtd , 0 )-> dev );
320+ bus = & codec -> bus -> core ;
321+ format_val = snd_hdac_calc_stream_format (runtime -> rate , runtime -> channels , runtime -> format ,
322+ runtime -> sample_bits , 0 );
323+
324+ snd_hdac_ext_stream_decouple (bus , link_stream , true);
325+ snd_hdac_ext_link_stream_reset (link_stream );
326+ snd_hdac_ext_link_stream_setup (link_stream , format_val );
327+
328+ link = snd_hdac_ext_bus_link_at (bus , codec -> core .addr );
329+ if (!link )
330+ return - EINVAL ;
331+
332+ if (substream -> stream == SNDRV_PCM_STREAM_PLAYBACK )
333+ snd_hdac_ext_link_set_stream_id (link , hdac_stream (link_stream )-> stream_tag );
334+
335+ ret = avs_dai_prepare (to_avs_dev (dai -> dev ), substream , dai );
336+ if (ret )
337+ return ret ;
338+
339+ link_stream -> link_prepared = true;
340+ return 0 ;
341+ }
342+
343+ static int avs_dai_hda_be_trigger (struct snd_pcm_substream * substream , int cmd ,
344+ struct snd_soc_dai * dai )
345+ {
346+ struct hdac_ext_stream * link_stream ;
347+ struct avs_dma_data * data ;
348+ int ret = 0 ;
349+
350+ dev_dbg (dai -> dev , "entry %s cmd=%d\n" , __func__ , cmd );
351+
352+ data = snd_soc_dai_get_dma_data (dai , substream );
353+ link_stream = substream -> runtime -> private_data ;
354+
355+ switch (cmd ) {
356+ case SNDRV_PCM_TRIGGER_START :
357+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE :
358+ snd_hdac_ext_link_stream_start (link_stream );
359+
360+ ret = avs_path_run (data -> path , AVS_TPLG_TRIGGER_AUTO );
361+ if (ret < 0 )
362+ dev_err (dai -> dev , "run BE path failed: %d\n" , ret );
363+ break ;
364+
365+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH :
366+ case SNDRV_PCM_TRIGGER_STOP :
367+ ret = avs_path_pause (data -> path );
368+ if (ret < 0 )
369+ dev_err (dai -> dev , "pause BE path failed: %d\n" , ret );
370+
371+ snd_hdac_ext_link_stream_clear (link_stream );
372+
373+ if (cmd == SNDRV_PCM_TRIGGER_STOP ) {
374+ ret = avs_path_reset (data -> path );
375+ if (ret < 0 )
376+ dev_err (dai -> dev , "reset BE path failed: %d\n" , ret );
377+ }
378+ break ;
379+
380+ default :
381+ ret = - EINVAL ;
382+ break ;
383+ }
384+
385+ return ret ;
386+ }
387+
388+ static const struct snd_soc_dai_ops avs_dai_hda_be_ops = {
389+ .startup = avs_dai_hda_be_startup ,
390+ .shutdown = avs_dai_hda_be_shutdown ,
391+ .hw_params = avs_dai_hda_be_hw_params ,
392+ .hw_free = avs_dai_hda_be_hw_free ,
393+ .prepare = avs_dai_hda_be_prepare ,
394+ .trigger = avs_dai_hda_be_trigger ,
395+ };
396+
248397static const unsigned int rates [] = {
249398 8000 , 11025 , 12000 , 16000 ,
250399 22050 , 24000 , 32000 , 44100 ,
@@ -831,3 +980,203 @@ int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned l
831980plat_register :
832981 return avs_soc_component_register (adev -> dev , name , & avs_component_driver , cpus , cpu_count );
833982}
983+
984+ /* HD-Audio CPU DAI template */
985+ static const struct snd_soc_dai_driver hda_cpu_dai = {
986+ .ops = & avs_dai_hda_be_ops ,
987+ .playback = {
988+ .channels_min = 1 ,
989+ .channels_max = 8 ,
990+ .rates = SNDRV_PCM_RATE_8000_192000 ,
991+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
992+ SNDRV_PCM_FMTBIT_S24_LE |
993+ SNDRV_PCM_FMTBIT_S32_LE ,
994+ },
995+ .capture = {
996+ .channels_min = 1 ,
997+ .channels_max = 8 ,
998+ .rates = SNDRV_PCM_RATE_8000_192000 ,
999+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
1000+ SNDRV_PCM_FMTBIT_S24_LE |
1001+ SNDRV_PCM_FMTBIT_S32_LE ,
1002+ },
1003+ };
1004+
1005+ static void avs_component_hda_unregister_dais (struct snd_soc_component * component )
1006+ {
1007+ struct snd_soc_acpi_mach * mach ;
1008+ struct snd_soc_dai * dai , * save ;
1009+ struct hda_codec * codec ;
1010+ char name [32 ];
1011+
1012+ mach = dev_get_platdata (component -> card -> dev );
1013+ codec = mach -> pdata ;
1014+ sprintf (name , "%s-cpu" , dev_name (& codec -> core .dev ));
1015+
1016+ for_each_component_dais_safe (component , dai , save ) {
1017+ if (!strstr (dai -> driver -> name , name ))
1018+ continue ;
1019+
1020+ if (dai -> playback_widget )
1021+ snd_soc_dapm_free_widget (dai -> playback_widget );
1022+ if (dai -> capture_widget )
1023+ snd_soc_dapm_free_widget (dai -> capture_widget );
1024+ snd_soc_unregister_dai (dai );
1025+ }
1026+ }
1027+
1028+ static int avs_component_hda_probe (struct snd_soc_component * component )
1029+ {
1030+ struct snd_soc_dapm_context * dapm ;
1031+ struct snd_soc_dai_driver * dais ;
1032+ struct snd_soc_acpi_mach * mach ;
1033+ struct hda_codec * codec ;
1034+ struct hda_pcm * pcm ;
1035+ const char * cname ;
1036+ int pcm_count = 0 , ret , i ;
1037+
1038+ mach = dev_get_platdata (component -> card -> dev );
1039+ if (!mach )
1040+ return - EINVAL ;
1041+
1042+ codec = mach -> pdata ;
1043+ if (list_empty (& codec -> pcm_list_head ))
1044+ return - EINVAL ;
1045+ list_for_each_entry (pcm , & codec -> pcm_list_head , list )
1046+ pcm_count ++ ;
1047+
1048+ dais = devm_kcalloc (component -> dev , pcm_count , sizeof (* dais ),
1049+ GFP_KERNEL );
1050+ if (!dais )
1051+ return - ENOMEM ;
1052+
1053+ cname = dev_name (& codec -> core .dev );
1054+ dapm = snd_soc_component_get_dapm (component );
1055+ pcm = list_first_entry (& codec -> pcm_list_head , struct hda_pcm , list );
1056+
1057+ for (i = 0 ; i < pcm_count ; i ++ , pcm = list_next_entry (pcm , list )) {
1058+ struct snd_soc_dai * dai ;
1059+
1060+ memcpy (& dais [i ], & hda_cpu_dai , sizeof (* dais ));
1061+ dais [i ].id = i ;
1062+ dais [i ].name = devm_kasprintf (component -> dev , GFP_KERNEL ,
1063+ "%s-cpu%d" , cname , i );
1064+ if (!dais [i ].name ) {
1065+ ret = - ENOMEM ;
1066+ goto exit ;
1067+ }
1068+
1069+ if (pcm -> stream [0 ].substreams ) {
1070+ dais [i ].playback .stream_name =
1071+ devm_kasprintf (component -> dev , GFP_KERNEL ,
1072+ "%s-cpu%d Tx" , cname , i );
1073+ if (!dais [i ].playback .stream_name ) {
1074+ ret = - ENOMEM ;
1075+ goto exit ;
1076+ }
1077+ }
1078+
1079+ if (pcm -> stream [1 ].substreams ) {
1080+ dais [i ].capture .stream_name =
1081+ devm_kasprintf (component -> dev , GFP_KERNEL ,
1082+ "%s-cpu%d Rx" , cname , i );
1083+ if (!dais [i ].capture .stream_name ) {
1084+ ret = - ENOMEM ;
1085+ goto exit ;
1086+ }
1087+ }
1088+
1089+ dai = snd_soc_register_dai (component , & dais [i ], false);
1090+ if (!dai ) {
1091+ dev_err (component -> dev , "register dai for %s failed\n" ,
1092+ pcm -> name );
1093+ ret = - EINVAL ;
1094+ goto exit ;
1095+ }
1096+
1097+ ret = snd_soc_dapm_new_dai_widgets (dapm , dai );
1098+ if (ret < 0 ) {
1099+ dev_err (component -> dev , "create widgets failed: %d\n" ,
1100+ ret );
1101+ goto exit ;
1102+ }
1103+ }
1104+
1105+ ret = avs_component_probe (component );
1106+ exit :
1107+ if (ret )
1108+ avs_component_hda_unregister_dais (component );
1109+
1110+ return ret ;
1111+ }
1112+
1113+ static void avs_component_hda_remove (struct snd_soc_component * component )
1114+ {
1115+ avs_component_hda_unregister_dais (component );
1116+ avs_component_remove (component );
1117+ }
1118+
1119+ static int avs_component_hda_open (struct snd_soc_component * component ,
1120+ struct snd_pcm_substream * substream )
1121+ {
1122+ struct snd_soc_pcm_runtime * rtd = snd_pcm_substream_chip (substream );
1123+ struct hdac_ext_stream * link_stream ;
1124+ struct hda_codec * codec ;
1125+
1126+ /* only BE DAI links are handled here */
1127+ if (!rtd -> dai_link -> no_pcm )
1128+ return avs_component_open (component , substream );
1129+
1130+ codec = dev_to_hda_codec (asoc_rtd_to_codec (rtd , 0 )-> dev );
1131+ link_stream = snd_hdac_ext_stream_assign (& codec -> bus -> core , substream ,
1132+ HDAC_EXT_STREAM_TYPE_LINK );
1133+ if (!link_stream )
1134+ return - EBUSY ;
1135+
1136+ substream -> runtime -> private_data = link_stream ;
1137+ return 0 ;
1138+ }
1139+
1140+ static int avs_component_hda_close (struct snd_soc_component * component ,
1141+ struct snd_pcm_substream * substream )
1142+ {
1143+ struct snd_soc_pcm_runtime * rtd = snd_pcm_substream_chip (substream );
1144+ struct hdac_ext_stream * link_stream ;
1145+
1146+ /* only BE DAI links are handled here */
1147+ if (!rtd -> dai_link -> no_pcm )
1148+ return 0 ;
1149+
1150+ link_stream = substream -> runtime -> private_data ;
1151+ snd_hdac_ext_stream_release (link_stream , HDAC_EXT_STREAM_TYPE_LINK );
1152+ substream -> runtime -> private_data = NULL ;
1153+
1154+ return 0 ;
1155+ }
1156+
1157+ static const struct snd_soc_component_driver avs_hda_component_driver = {
1158+ .name = "avs-hda-pcm" ,
1159+ .probe = avs_component_hda_probe ,
1160+ .remove = avs_component_hda_remove ,
1161+ .open = avs_component_hda_open ,
1162+ .close = avs_component_hda_close ,
1163+ .pointer = avs_component_pointer ,
1164+ .mmap = avs_component_mmap ,
1165+ .pcm_construct = avs_component_construct ,
1166+ /*
1167+ * hda platform component's probe() is dependent on
1168+ * codec->pcm_list_head, it needs to be initialized after codec
1169+ * component. remove_order is here for completeness sake
1170+ */
1171+ .probe_order = SND_SOC_COMP_ORDER_LATE ,
1172+ .remove_order = SND_SOC_COMP_ORDER_EARLY ,
1173+ .module_get_upon_open = 1 ,
1174+ .topology_name_prefix = "intel/avs" ,
1175+ .non_legacy_dai_naming = true,
1176+ };
1177+
1178+ int avs_hda_platform_register (struct avs_dev * adev , const char * name )
1179+ {
1180+ return avs_soc_component_register (adev -> dev , name ,
1181+ & avs_hda_component_driver , NULL , 0 );
1182+ }
0 commit comments