@@ -42,6 +42,7 @@ struct dcp_audio {
4242 unsigned int open_cookie ;
4343
4444 struct mutex data_lock ;
45+ bool dcp_connected ; /// dcp status keep for delayed initialization
4546 bool connected ;
4647 unsigned int connection_cookie ;
4748
@@ -428,19 +429,8 @@ static int dcpaud_create_pcm(struct dcp_audio *dcpaud)
428429{
429430 struct snd_card * card = dcpaud -> card ;
430431 struct snd_pcm * pcm ;
431- struct dma_chan * chan ;
432432 int ret ;
433433
434- chan = of_dma_request_slave_channel (dcpaud -> dev -> of_node , "tx" );
435- if (IS_ERR_OR_NULL (chan )) {
436- if (!chan )
437- return - EINVAL ;
438-
439- dev_err (dcpaud -> dev , "can't request audio TX DMA channel: %pE\n" , chan );
440- return PTR_ERR (chan );
441- }
442- dcpaud -> chan = chan ;
443-
444434#define NUM_PLAYBACK 1
445435#define NUM_CAPTURE 0
446436
@@ -451,7 +441,7 @@ static int dcpaud_create_pcm(struct dcp_audio *dcpaud)
451441 snd_pcm_set_ops (pcm , SNDRV_PCM_STREAM_PLAYBACK , & dcp_playback_ops );
452442 dcpaud -> substream = pcm -> streams [SNDRV_PCM_STREAM_PLAYBACK ].substream ;
453443 snd_pcm_set_managed_buffer (dcpaud -> substream , SNDRV_DMA_TYPE_DEV_IRAM ,
454- chan -> device -> dev , 1024 * 1024 ,
444+ dcpaud -> chan -> device -> dev , 1024 * 1024 ,
455445 SIZE_MAX );
456446
457447 pcm -> nonatomic = true;
@@ -461,12 +451,12 @@ static int dcpaud_create_pcm(struct dcp_audio *dcpaud)
461451 return 0 ;
462452}
463453
454+ /* expects to be called with data_lock locked and unlocks it */
464455static void dcpaud_report_hotplug (struct dcp_audio * dcpaud , bool connected )
465456{
466457 struct snd_pcm_substream * substream = dcpaud -> substream ;
467458
468- mutex_lock (& dcpaud -> data_lock );
469- if (dcpaud -> connected == connected ) {
459+ if (!dcpaud -> card || dcpaud -> connected == connected ) {
470460 mutex_unlock (& dcpaud -> data_lock );
471461 return ;
472462 }
@@ -502,6 +492,53 @@ static void dcpaud_set_card_names(struct dcp_audio *dcpaud)
502492 strcpy (card -> shortname , "Apple DisplayPort" );
503493}
504494
495+ static int dcpaud_init_snd_card (struct dcp_audio * dcpaud )
496+ {
497+ int ret ;
498+ struct dma_chan * chan ;
499+
500+ chan = of_dma_request_slave_channel (dcpaud -> dev -> of_node , "tx" );
501+ /* squelch dma channel request errors, the driver will try again alter */
502+ if (!chan ) {
503+ dev_warn (dcpaud -> dev , "audio TX DMA channel request failed\n" );
504+ return 0 ;
505+ } else if (IS_ERR (chan )) {
506+ dev_warn (dcpaud -> dev , "audio TX DMA channel request failed: %pE\n" , chan );
507+ return 0 ;
508+ }
509+ dcpaud -> chan = chan ;
510+
511+ ret = snd_card_new (dcpaud -> dev , SNDRV_DEFAULT_IDX1 , SNDRV_DEFAULT_STR1 ,
512+ THIS_MODULE , 0 , & dcpaud -> card );
513+ if (ret )
514+ return ret ;
515+
516+ dcpaud_set_card_names (dcpaud );
517+
518+ ret = dcpaud_create_pcm (dcpaud );
519+ if (ret )
520+ goto err_free_card ;
521+
522+ ret = dcpaud_create_chmap_ctl (dcpaud );
523+ if (ret )
524+ goto err_free_card ;
525+
526+ ret = dcpaud_create_jack (dcpaud );
527+ if (ret )
528+ goto err_free_card ;
529+
530+ ret = snd_card_register (dcpaud -> card );
531+ if (ret )
532+ goto err_free_card ;
533+
534+ return 0 ;
535+ err_free_card :
536+ dev_warn (dcpaud -> dev , "Failed to initialize sound card: %d\n" , ret );
537+ snd_card_free (dcpaud -> card );
538+ dcpaud -> card = NULL ;
539+ return ret ;
540+ }
541+
505542#ifdef CONFIG_SND_DEBUG
506543static void dcpaud_expose_debugfs_blob (struct dcp_audio * dcpaud , const char * name , void * base , size_t size )
507544{
@@ -520,15 +557,59 @@ static void dcpaud_expose_debugfs_blob(struct dcp_audio *dcpaud, const char *nam
520557void dcpaud_connect (struct platform_device * pdev , bool connected )
521558{
522559 struct dcp_audio * dcpaud = platform_get_drvdata (pdev );
560+
561+ mutex_lock (& dcpaud -> data_lock );
562+
563+ if (!dcpaud -> chan ) {
564+ int ret = dcpaud_init_snd_card (dcpaud );
565+ if (ret ) {
566+ dcpaud -> dcp_connected = connected ;
567+ mutex_unlock (& dcpaud -> data_lock );
568+ return ;
569+ }
570+ }
523571 dcpaud_report_hotplug (dcpaud , connected );
524572}
525573
526574void dcpaud_disconnect (struct platform_device * pdev )
527575{
528576 struct dcp_audio * dcpaud = platform_get_drvdata (pdev );
577+
578+ mutex_lock (& dcpaud -> data_lock );
579+
580+ dcpaud -> dcp_connected = false;
529581 dcpaud_report_hotplug (dcpaud , false);
530582}
531583
584+ static ssize_t probe_snd_card_store (struct device * dev ,
585+ struct device_attribute * attr ,
586+ const char * buf , size_t count )
587+ {
588+ int ret ;
589+ bool connected = false;
590+ struct dcp_audio * dcpaud = dev_get_drvdata (dev );
591+
592+ mutex_lock (& dcpaud -> data_lock );
593+
594+ if (!dcpaud -> chan ) {
595+ ret = dcpaud_init_snd_card (dcpaud );
596+ if (ret )
597+ goto out_unlock ;
598+
599+ connected = dcpaud -> dcp_connected ;
600+ if (connected ) {
601+ dcpaud_report_hotplug (dcpaud , connected );
602+ goto out ;
603+ }
604+ }
605+ out_unlock :
606+ mutex_unlock (& dcpaud -> data_lock );
607+ out :
608+ return count ;
609+ }
610+
611+ static const DEVICE_ATTR_WO (probe_snd_card );
612+
532613static int dcpaud_comp_bind (struct device * dev , struct device * main , void * data )
533614{
534615 struct dcp_audio * dcpaud = dev_get_drvdata (dev );
@@ -551,46 +632,28 @@ static int dcpaud_comp_bind(struct device *dev, struct device *main, void *data)
551632 dcp_pdev = of_find_device_by_node (dcp_node );
552633 of_node_put (dcp_node );
553634 if (!dcp_pdev ) {
554- dev_info (dev , "No DP/HDMI audio device not ready\n" );
635+ dev_info (dev , "No DP/HDMI audio device, dcp not ready\n" );
555636 return 0 ;
556637 }
557638 dcpaud -> dcp_dev = & dcp_pdev -> dev ;
558639
559- ret = snd_card_new (dev , SNDRV_DEFAULT_IDX1 , SNDRV_DEFAULT_STR1 ,
560- THIS_MODULE , 0 , & dcpaud -> card );
561- if (ret )
562- return ret ;
563-
564- dcpaud_set_card_names (dcpaud );
565-
566- ret = dcpaud_create_pcm (dcpaud );
567- if (ret )
568- goto err_free_card ;
569-
570- ret = dcpaud_create_chmap_ctl (dcpaud );
571- if (ret )
572- goto err_free_card ;
573-
574- ret = dcpaud_create_jack (dcpaud );
575- if (ret )
576- goto err_free_card ;
577-
578- ret = snd_card_register (dcpaud -> card );
579- if (ret )
580- goto err_free_card ;
581-
582640 dcpaud_expose_debugfs_blob (dcpaud , "selected_cookie" , & dcpaud -> selected_cookie ,
583641 sizeof (dcpaud -> selected_cookie ));
584642 dcpaud_expose_debugfs_blob (dcpaud , "elements" , dcpaud -> elements ,
585643 DCPAUD_ELEMENTS_MAXSIZE );
586644 dcpaud_expose_debugfs_blob (dcpaud , "product_attrs" , dcpaud -> productattrs ,
587645 DCPAUD_PRODUCTATTRS_MAXSIZE );
588646
589- return 0 ;
647+ mutex_lock (& dcpaud -> data_lock );
648+ /* ignore errors to prevent audio issues affecting the display side */
649+ dcpaud_init_snd_card (dcpaud );
650+ mutex_unlock (& dcpaud -> data_lock );
590651
591- err_free_card :
592- snd_card_free (dcpaud -> card );
593- return ret ;
652+ ret = device_create_file (dev , & dev_attr_probe_snd_card );
653+ if (ret )
654+ dev_info (dev , "creating force probe sysfs file failed: %d\n" , ret );
655+
656+ return 0 ;
594657}
595658
596659static void dcpaud_comp_unbind (struct device * dev , struct device * main ,
0 commit comments