@@ -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
@@ -430,19 +431,8 @@ static int dcpaud_create_pcm(struct dcp_audio *dcpaud)
430431{
431432 struct snd_card * card = dcpaud -> card ;
432433 struct snd_pcm * pcm ;
433- struct dma_chan * chan ;
434434 int ret ;
435435
436- chan = of_dma_request_slave_channel (dcpaud -> dev -> of_node , "tx" );
437- if (IS_ERR_OR_NULL (chan )) {
438- if (!chan )
439- return - EINVAL ;
440-
441- dev_err (dcpaud -> dev , "can't request audio TX DMA channel: %pE\n" , chan );
442- return PTR_ERR (chan );
443- }
444- dcpaud -> chan = chan ;
445-
446436#define NUM_PLAYBACK 1
447437#define NUM_CAPTURE 0
448438
@@ -453,7 +443,7 @@ static int dcpaud_create_pcm(struct dcp_audio *dcpaud)
453443 snd_pcm_set_ops (pcm , SNDRV_PCM_STREAM_PLAYBACK , & dcp_playback_ops );
454444 dcpaud -> substream = pcm -> streams [SNDRV_PCM_STREAM_PLAYBACK ].substream ;
455445 snd_pcm_set_managed_buffer (dcpaud -> substream , SNDRV_DMA_TYPE_DEV_IRAM ,
456- chan -> device -> dev , 1024 * 1024 ,
446+ dcpaud -> chan -> device -> dev , 1024 * 1024 ,
457447 SIZE_MAX );
458448
459449 pcm -> nonatomic = true;
@@ -463,12 +453,12 @@ static int dcpaud_create_pcm(struct dcp_audio *dcpaud)
463453 return 0 ;
464454}
465455
456+ /* expects to be called with data_lock locked and unlocks it */
466457static void dcpaud_report_hotplug (struct dcp_audio * dcpaud , bool connected )
467458{
468459 struct snd_pcm_substream * substream = dcpaud -> substream ;
469460
470- mutex_lock (& dcpaud -> data_lock );
471- if (dcpaud -> connected == connected ) {
461+ if (!dcpaud -> card || dcpaud -> connected == connected ) {
472462 mutex_unlock (& dcpaud -> data_lock );
473463 return ;
474464 }
@@ -504,6 +494,53 @@ static void dcpaud_set_card_names(struct dcp_audio *dcpaud)
504494 strscpy (card -> shortname , "Apple DisplayPort" , sizeof (card -> shortname ));
505495}
506496
497+ static int dcpaud_init_snd_card (struct dcp_audio * dcpaud )
498+ {
499+ int ret ;
500+ struct dma_chan * chan ;
501+
502+ chan = of_dma_request_slave_channel (dcpaud -> dev -> of_node , "tx" );
503+ /* squelch dma channel request errors, the driver will try again alter */
504+ if (!chan ) {
505+ dev_warn (dcpaud -> dev , "audio TX DMA channel request failed\n" );
506+ return 0 ;
507+ } else if (IS_ERR (chan )) {
508+ dev_warn (dcpaud -> dev , "audio TX DMA channel request failed: %pE\n" , chan );
509+ return 0 ;
510+ }
511+ dcpaud -> chan = chan ;
512+
513+ ret = snd_card_new (dcpaud -> dev , SNDRV_DEFAULT_IDX1 , SNDRV_DEFAULT_STR1 ,
514+ THIS_MODULE , 0 , & dcpaud -> card );
515+ if (ret )
516+ return ret ;
517+
518+ dcpaud_set_card_names (dcpaud );
519+
520+ ret = dcpaud_create_pcm (dcpaud );
521+ if (ret )
522+ goto err_free_card ;
523+
524+ ret = dcpaud_create_chmap_ctl (dcpaud );
525+ if (ret )
526+ goto err_free_card ;
527+
528+ ret = dcpaud_create_jack (dcpaud );
529+ if (ret )
530+ goto err_free_card ;
531+
532+ ret = snd_card_register (dcpaud -> card );
533+ if (ret )
534+ goto err_free_card ;
535+
536+ return 0 ;
537+ err_free_card :
538+ dev_warn (dcpaud -> dev , "Failed to initialize sound card: %d\n" , ret );
539+ snd_card_free (dcpaud -> card );
540+ dcpaud -> card = NULL ;
541+ return ret ;
542+ }
543+
507544#ifdef CONFIG_SND_DEBUG
508545static void dcpaud_expose_debugfs_blob (struct dcp_audio * dcpaud , const char * name , void * base , size_t size )
509546{
@@ -522,15 +559,59 @@ static void dcpaud_expose_debugfs_blob(struct dcp_audio *dcpaud, const char *nam
522559void dcpaud_connect (struct platform_device * pdev , bool connected )
523560{
524561 struct dcp_audio * dcpaud = platform_get_drvdata (pdev );
562+
563+ mutex_lock (& dcpaud -> data_lock );
564+
565+ if (!dcpaud -> chan ) {
566+ int ret = dcpaud_init_snd_card (dcpaud );
567+ if (ret ) {
568+ dcpaud -> dcp_connected = connected ;
569+ mutex_unlock (& dcpaud -> data_lock );
570+ return ;
571+ }
572+ }
525573 dcpaud_report_hotplug (dcpaud , connected );
526574}
527575
528576void dcpaud_disconnect (struct platform_device * pdev )
529577{
530578 struct dcp_audio * dcpaud = platform_get_drvdata (pdev );
579+
580+ mutex_lock (& dcpaud -> data_lock );
581+
582+ dcpaud -> dcp_connected = false;
531583 dcpaud_report_hotplug (dcpaud , false);
532584}
533585
586+ static ssize_t probe_snd_card_store (struct device * dev ,
587+ struct device_attribute * attr ,
588+ const char * buf , size_t count )
589+ {
590+ int ret ;
591+ bool connected = false;
592+ struct dcp_audio * dcpaud = dev_get_drvdata (dev );
593+
594+ mutex_lock (& dcpaud -> data_lock );
595+
596+ if (!dcpaud -> chan ) {
597+ ret = dcpaud_init_snd_card (dcpaud );
598+ if (ret )
599+ goto out_unlock ;
600+
601+ connected = dcpaud -> dcp_connected ;
602+ if (connected ) {
603+ dcpaud_report_hotplug (dcpaud , connected );
604+ goto out ;
605+ }
606+ }
607+ out_unlock :
608+ mutex_unlock (& dcpaud -> data_lock );
609+ out :
610+ return count ;
611+ }
612+
613+ static const DEVICE_ATTR_WO (probe_snd_card );
614+
534615static int dcpaud_comp_bind (struct device * dev , struct device * main , void * data )
535616{
536617 struct dcp_audio * dcpaud = dev_get_drvdata (dev );
@@ -553,46 +634,28 @@ static int dcpaud_comp_bind(struct device *dev, struct device *main, void *data)
553634 dcp_pdev = of_find_device_by_node (dcp_node );
554635 of_node_put (dcp_node );
555636 if (!dcp_pdev ) {
556- dev_info (dev , "No DP/HDMI audio device not ready\n" );
637+ dev_info (dev , "No DP/HDMI audio device, dcp not ready\n" );
557638 return 0 ;
558639 }
559640 dcpaud -> dcp_dev = & dcp_pdev -> dev ;
560641
561- ret = snd_card_new (dev , SNDRV_DEFAULT_IDX1 , SNDRV_DEFAULT_STR1 ,
562- THIS_MODULE , 0 , & dcpaud -> card );
563- if (ret )
564- return ret ;
565-
566- dcpaud_set_card_names (dcpaud );
567-
568- ret = dcpaud_create_pcm (dcpaud );
569- if (ret )
570- goto err_free_card ;
571-
572- ret = dcpaud_create_chmap_ctl (dcpaud );
573- if (ret )
574- goto err_free_card ;
575-
576- ret = dcpaud_create_jack (dcpaud );
577- if (ret )
578- goto err_free_card ;
579-
580- ret = snd_card_register (dcpaud -> card );
581- if (ret )
582- goto err_free_card ;
583-
584642 dcpaud_expose_debugfs_blob (dcpaud , "selected_cookie" , & dcpaud -> selected_cookie ,
585643 sizeof (dcpaud -> selected_cookie ));
586644 dcpaud_expose_debugfs_blob (dcpaud , "elements" , dcpaud -> elements ,
587645 DCPAUD_ELEMENTS_MAXSIZE );
588646 dcpaud_expose_debugfs_blob (dcpaud , "product_attrs" , dcpaud -> productattrs ,
589647 DCPAUD_PRODUCTATTRS_MAXSIZE );
590648
591- return 0 ;
649+ mutex_lock (& dcpaud -> data_lock );
650+ /* ignore errors to prevent audio issues affecting the display side */
651+ dcpaud_init_snd_card (dcpaud );
652+ mutex_unlock (& dcpaud -> data_lock );
592653
593- err_free_card :
594- snd_card_free (dcpaud -> card );
595- return ret ;
654+ ret = device_create_file (dev , & dev_attr_probe_snd_card );
655+ if (ret )
656+ dev_info (dev , "creating force probe sysfs file failed: %d\n" , ret );
657+
658+ return 0 ;
596659}
597660
598661static void dcpaud_comp_unbind (struct device * dev , struct device * main ,
0 commit comments