1111
1212#define DEBUG
1313
14+ #include <linux/component.h>
1415#include <linux/debugfs.h>
1516#include <linux/device.h>
1617#include <linux/of_dma.h>
18+ #include <linux/of_graph.h>
19+ #include <linux/of_platform.h>
1720#include <linux/platform_device.h>
1821#include <sound/dmaengine_pcm.h>
1922#include <sound/pcm.h>
2225#include <sound/jack.h>
2326
2427#include "av.h"
28+ #include "dcp.h"
2529#include "audio.h"
2630#include "parser.h"
2731
2832#define DCPAUD_ELEMENTS_MAXSIZE 16384
2933#define DCPAUD_PRODUCTATTRS_MAXSIZE 1024
3034
31- #define DRV_NAME "dcp-hdmi-audio"
32-
3335struct dcp_audio {
3436 struct device * dev ;
35- struct dcp_audio_pdata * pdata ;
37+ struct device * dcp_dev ;
3638 struct dma_chan * chan ;
3739 struct snd_card * card ;
3840 struct snd_jack * jack ;
@@ -72,12 +74,12 @@ static int dcpaud_read_remote_info(struct dcp_audio *dcpaud)
7274{
7375 int ret ;
7476
75- ret = dcp_audiosrv_get_elements (dcpaud -> pdata -> dcp_dev , dcpaud -> elements ,
77+ ret = dcp_audiosrv_get_elements (dcpaud -> dcp_dev , dcpaud -> elements ,
7678 DCPAUD_ELEMENTS_MAXSIZE );
7779 if (ret < 0 )
7880 return ret ;
7981
80- ret = dcp_audiosrv_get_product_attrs (dcpaud -> pdata -> dcp_dev , dcpaud -> productattrs ,
82+ ret = dcp_audiosrv_get_product_attrs (dcpaud -> dcp_dev , dcpaud -> productattrs ,
8183 DCPAUD_PRODUCTATTRS_MAXSIZE );
8284 if (ret < 0 )
8385 return ret ;
@@ -128,7 +130,7 @@ static void dcpaud_consult_elements(struct dcp_audio *dcpaud,
128130{
129131 struct dcp_sound_format_mask sieve ;
130132 struct dcp_parse_ctx elements = {
131- .dcp = dev_get_drvdata (dcpaud -> pdata -> dcp_dev ),
133+ .dcp = dev_get_drvdata (dcpaud -> dcp_dev ),
132134 .blob = dcpaud -> elements + 4 ,
133135 .len = DCPAUD_ELEMENTS_MAXSIZE - 4 ,
134136 .pos = 0 ,
@@ -145,7 +147,7 @@ static int dcpaud_select_cookie(struct dcp_audio *dcpaud,
145147{
146148 struct dcp_sound_format_mask sieve ;
147149 struct dcp_parse_ctx elements = {
148- .dcp = dev_get_drvdata (dcpaud -> pdata -> dcp_dev ),
150+ .dcp = dev_get_drvdata (dcpaud -> dcp_dev ),
149151 .blob = dcpaud -> elements + 4 ,
150152 .len = DCPAUD_ELEMENTS_MAXSIZE - 4 ,
151153 .pos = 0 ,
@@ -317,7 +319,7 @@ static int dcp_pcm_hw_free(struct snd_pcm_substream *substream)
317319 if (!dcpaud_connection_up (dcpaud ))
318320 return 0 ;
319321
320- return dcp_audiosrv_unprepare (dcpaud -> pdata -> dcp_dev );
322+ return dcp_audiosrv_unprepare (dcpaud -> dcp_dev );
321323}
322324
323325static int dcp_pcm_prepare (struct snd_pcm_substream * substream )
@@ -327,7 +329,7 @@ static int dcp_pcm_prepare(struct snd_pcm_substream *substream)
327329 if (!dcpaud_connection_up (dcpaud ))
328330 return - ENXIO ;
329331
330- return dcp_audiosrv_prepare (dcpaud -> pdata -> dcp_dev ,
332+ return dcp_audiosrv_prepare (dcpaud -> dcp_dev ,
331333 & dcpaud -> selected_cookie );
332334}
333335
@@ -342,7 +344,7 @@ static int dcp_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
342344 if (!dcpaud_connection_up (dcpaud ))
343345 return - ENXIO ;
344346
345- ret = dcp_audiosrv_startlink (dcpaud -> pdata -> dcp_dev ,
347+ ret = dcp_audiosrv_startlink (dcpaud -> dcp_dev ,
346348 & dcpaud -> selected_cookie );
347349 if (ret < 0 )
348350 return ret ;
@@ -367,7 +369,7 @@ static int dcp_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
367369
368370 case SNDRV_PCM_TRIGGER_STOP :
369371 case SNDRV_PCM_TRIGGER_SUSPEND :
370- ret = dcp_audiosrv_stoplink (dcpaud -> pdata -> dcp_dev );
372+ ret = dcp_audiosrv_stoplink (dcpaud -> dcp_dev );
371373 if (ret < 0 )
372374 return ret ;
373375 break ;
@@ -431,7 +433,7 @@ static int dcpaud_create_pcm(struct dcp_audio *dcpaud)
431433 struct dma_chan * chan ;
432434 int ret ;
433435
434- chan = of_dma_request_slave_channel (dcpaud -> pdata -> dpaudio_node , "tx" );
436+ chan = of_dma_request_slave_channel (dcpaud -> dev -> of_node , "tx" );
435437 if (IS_ERR_OR_NULL (chan )) {
436438 if (!chan )
437439 return - EINVAL ;
@@ -461,9 +463,8 @@ static int dcpaud_create_pcm(struct dcp_audio *dcpaud)
461463 return 0 ;
462464}
463465
464- static void dcpaud_report_hotplug (struct device * dev , bool connected )
466+ static void dcpaud_report_hotplug (struct dcp_audio * dcpaud , bool connected )
465467{
466- struct dcp_audio * dcpaud = dev_get_drvdata (dev );
467468 struct snd_pcm_substream * substream = dcpaud -> substream ;
468469
469470 mutex_lock (& dcpaud -> data_lock );
@@ -518,30 +519,44 @@ static void dcpaud_expose_debugfs_blob(struct dcp_audio *dcpaud, const char *nam
518519static void dcpaud_expose_debugfs_blob (struct dcp_audio * dcpaud , const char * name , void * base , size_t size ) {}
519520#endif
520521
521- static int dcpaud_probe (struct platform_device * pdev )
522+ void dcpaud_connect (struct platform_device * pdev , bool connected )
522523{
523- struct device * dev = & pdev -> dev ;
524- struct dcp_audio_pdata * pdata = dev -> platform_data ;
525- struct dcp_audio * dcpaud ;
526- int ret ;
524+ struct dcp_audio * dcpaud = platform_get_drvdata (pdev );
525+ dcpaud_report_hotplug (dcpaud , connected );
526+ }
527527
528- dcpaud = devm_kzalloc (dev , sizeof (* dcpaud ), GFP_KERNEL );
529- if (!dcpaud )
530- return - ENOMEM ;
531- dcpaud -> dev = dev ;
532- dcpaud -> pdata = pdata ;
533- mutex_init (& dcpaud -> data_lock );
534- platform_set_drvdata (pdev , dcpaud );
528+ void dcpaud_disconnect (struct platform_device * pdev )
529+ {
530+ struct dcp_audio * dcpaud = platform_get_drvdata (pdev );
531+ dcpaud_report_hotplug (dcpaud , false);
532+ }
535533
536- dcpaud -> elements = devm_kzalloc (dev , DCPAUD_ELEMENTS_MAXSIZE ,
537- GFP_KERNEL );
538- if (!dcpaud -> elements )
539- return - ENOMEM ;
534+ static int dcpaud_comp_bind (struct device * dev , struct device * main , void * data )
535+ {
536+ struct dcp_audio * dcpaud = dev_get_drvdata (dev );
537+ struct device_node * endpoint , * dcp_node = NULL ;
538+ struct platform_device * dcp_pdev ;
539+ int ret ;
540540
541- dcpaud -> productattrs = devm_kzalloc (dev , DCPAUD_PRODUCTATTRS_MAXSIZE ,
542- GFP_KERNEL );
543- if (!dcpaud -> productattrs )
544- return - ENOMEM ;
541+ /* find linked DCP instance */
542+ endpoint = of_graph_get_endpoint_by_regs (dev -> of_node , 0 , 0 );
543+ if (endpoint ) {
544+ dcp_node = of_graph_get_remote_port_parent (endpoint );
545+ of_node_put (endpoint );
546+ }
547+ if (!dcp_node || !of_device_is_available (dcp_node )) {
548+ of_node_put (dcp_node );
549+ dev_info (dev , "No audio support\n" );
550+ return 0 ;
551+ }
552+
553+ dcp_pdev = of_find_device_by_node (dcp_node );
554+ of_node_put (dcp_node );
555+ if (!dcp_pdev ) {
556+ dev_info (dev , "No DP/HDMI audio device not ready\n" );
557+ return 0 ;
558+ }
559+ dcpaud -> dcp_dev = & dcp_pdev -> dev ;
545560
546561 ret = snd_card_new (dev , SNDRV_DEFAULT_IDX1 , SNDRV_DEFAULT_STR1 ,
547562 THIS_MODULE , 0 , & dcpaud -> card );
@@ -573,31 +588,77 @@ static int dcpaud_probe(struct platform_device *pdev)
573588 dcpaud_expose_debugfs_blob (dcpaud , "product_attrs" , dcpaud -> productattrs ,
574589 DCPAUD_PRODUCTATTRS_MAXSIZE );
575590
576- dcp_audiosrv_set_hotplug_cb (pdata -> dcp_dev , dev , dcpaud_report_hotplug );
577-
578591 return 0 ;
579592
580593err_free_card :
581594 snd_card_free (dcpaud -> card );
582595 return ret ;
583596}
584597
585- static int dcpaud_remove (struct platform_device * dev )
598+ static void dcpaud_comp_unbind (struct device * dev , struct device * main ,
599+ void * data )
586600{
587- struct dcp_audio * dcpaud = platform_get_drvdata (dev );
601+ struct dcp_audio * dcpaud = dev_get_drvdata (dev );
588602
589- dcp_audiosrv_set_hotplug_cb (dcpaud -> pdata -> dcp_dev , NULL , NULL );
590- snd_card_free (dcpaud -> card );
603+ /* snd_card_free_when_closed() checks for NULL */
604+ snd_card_free_when_closed (dcpaud -> card );
605+ }
591606
592- return 0 ;
607+ static const struct component_ops dcpaud_comp_ops = {
608+ .bind = dcpaud_comp_bind ,
609+ .unbind = dcpaud_comp_unbind ,
610+ };
611+
612+ static int dcpaud_probe (struct platform_device * pdev )
613+ {
614+ struct dcp_audio * dcpaud ;
615+
616+ dcpaud = devm_kzalloc (& pdev -> dev , sizeof (* dcpaud ), GFP_KERNEL );
617+ if (!dcpaud )
618+ return - ENOMEM ;
619+
620+ dcpaud -> elements = devm_kzalloc (& pdev -> dev , DCPAUD_ELEMENTS_MAXSIZE ,
621+ GFP_KERNEL );
622+ if (!dcpaud -> elements )
623+ return - ENOMEM ;
624+
625+ dcpaud -> productattrs = devm_kzalloc (& pdev -> dev , DCPAUD_PRODUCTATTRS_MAXSIZE ,
626+ GFP_KERNEL );
627+ if (!dcpaud -> productattrs )
628+ return - ENOMEM ;
629+
630+ dcpaud -> dev = & pdev -> dev ;
631+ mutex_init (& dcpaud -> data_lock );
632+ platform_set_drvdata (pdev , dcpaud );
633+
634+ return component_add (& pdev -> dev , & dcpaud_comp_ops );
593635}
594636
637+ static void dcpaud_remove (struct platform_device * pdev )
638+ {
639+ component_del (& pdev -> dev , & dcpaud_comp_ops );
640+ }
641+
642+ static void dcpaud_shutdown (struct platform_device * pdev )
643+ {
644+ component_del (& pdev -> dev , & dcpaud_comp_ops );
645+ }
646+
647+ // static DEFINE_SIMPLE_DEV_PM_OPS(dcpaud_pm_ops, dcpaud_suspend, dcpaud_resume);
648+
649+ static const struct of_device_id dcpaud_of_match [] = {
650+ { .compatible = "apple,dpaudio" },
651+ {}
652+ };
653+
595654static struct platform_driver dcpaud_driver = {
596655 .driver = {
597- .name = DRV_NAME ,
656+ .name = "dcp-dp-audio" ,
657+ .of_match_table = dcpaud_of_match ,
598658 },
599- .probe = dcpaud_probe ,
600- .remove = dcpaud_remove ,
659+ .probe = dcpaud_probe ,
660+ .remove = dcpaud_remove ,
661+ .shutdown = dcpaud_shutdown ,
601662};
602663
603664void __init dcp_audio_register (void )
0 commit comments