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 ;
@@ -429,7 +431,7 @@ static int dcpaud_create_pcm(struct dcp_audio *dcpaud)
429431 struct dma_chan * chan ;
430432 int ret ;
431433
432- chan = of_dma_request_slave_channel (dcpaud -> pdata -> dpaudio_node , "tx" );
434+ chan = of_dma_request_slave_channel (dcpaud -> dev -> of_node , "tx" );
433435 if (IS_ERR_OR_NULL (chan )) {
434436 if (!chan )
435437 return - EINVAL ;
@@ -459,9 +461,8 @@ static int dcpaud_create_pcm(struct dcp_audio *dcpaud)
459461 return 0 ;
460462}
461463
462- static void dcpaud_report_hotplug (struct device * dev , bool connected )
464+ static void dcpaud_report_hotplug (struct dcp_audio * dcpaud , bool connected )
463465{
464- struct dcp_audio * dcpaud = dev_get_drvdata (dev );
465466 struct snd_pcm_substream * substream = dcpaud -> substream ;
466467
467468 mutex_lock (& dcpaud -> data_lock );
@@ -516,30 +517,44 @@ static void dcpaud_expose_debugfs_blob(struct dcp_audio *dcpaud, const char *nam
516517static void dcpaud_expose_debugfs_blob (struct dcp_audio * dcpaud , const char * name , void * base , size_t size ) {}
517518#endif
518519
519- static int dcpaud_probe (struct platform_device * pdev )
520+ void dcpaud_connect (struct platform_device * pdev , bool connected )
520521{
521- struct device * dev = & pdev -> dev ;
522- struct dcp_audio_pdata * pdata = dev -> platform_data ;
523- struct dcp_audio * dcpaud ;
524- int ret ;
522+ struct dcp_audio * dcpaud = platform_get_drvdata (pdev );
523+ dcpaud_report_hotplug (dcpaud , connected );
524+ }
525525
526- dcpaud = devm_kzalloc (dev , sizeof (* dcpaud ), GFP_KERNEL );
527- if (!dcpaud )
528- return - ENOMEM ;
529- dcpaud -> dev = dev ;
530- dcpaud -> pdata = pdata ;
531- mutex_init (& dcpaud -> data_lock );
532- platform_set_drvdata (pdev , dcpaud );
526+ void dcpaud_disconnect (struct platform_device * pdev )
527+ {
528+ struct dcp_audio * dcpaud = platform_get_drvdata (pdev );
529+ dcpaud_report_hotplug (dcpaud , false);
530+ }
533531
534- dcpaud -> elements = devm_kzalloc (dev , DCPAUD_ELEMENTS_MAXSIZE ,
535- GFP_KERNEL );
536- if (!dcpaud -> elements )
537- return - ENOMEM ;
532+ static int dcpaud_comp_bind (struct device * dev , struct device * main , void * data )
533+ {
534+ struct dcp_audio * dcpaud = dev_get_drvdata (dev );
535+ struct device_node * endpoint , * dcp_node = NULL ;
536+ struct platform_device * dcp_pdev ;
537+ int ret ;
538538
539- dcpaud -> productattrs = devm_kzalloc (dev , DCPAUD_PRODUCTATTRS_MAXSIZE ,
540- GFP_KERNEL );
541- if (!dcpaud -> productattrs )
542- return - ENOMEM ;
539+ /* find linked DCP instance */
540+ endpoint = of_graph_get_endpoint_by_regs (dev -> of_node , 0 , 0 );
541+ if (endpoint ) {
542+ dcp_node = of_graph_get_remote_port_parent (endpoint );
543+ of_node_put (endpoint );
544+ }
545+ if (!dcp_node || !of_device_is_available (dcp_node )) {
546+ of_node_put (dcp_node );
547+ dev_info (dev , "No audio support\n" );
548+ return 0 ;
549+ }
550+
551+ dcp_pdev = of_find_device_by_node (dcp_node );
552+ of_node_put (dcp_node );
553+ if (!dcp_pdev ) {
554+ dev_info (dev , "No DP/HDMI audio device not ready\n" );
555+ return 0 ;
556+ }
557+ dcpaud -> dcp_dev = & dcp_pdev -> dev ;
543558
544559 ret = snd_card_new (dev , SNDRV_DEFAULT_IDX1 , SNDRV_DEFAULT_STR1 ,
545560 THIS_MODULE , 0 , & dcpaud -> card );
@@ -571,31 +586,78 @@ static int dcpaud_probe(struct platform_device *pdev)
571586 dcpaud_expose_debugfs_blob (dcpaud , "product_attrs" , dcpaud -> productattrs ,
572587 DCPAUD_PRODUCTATTRS_MAXSIZE );
573588
574- dcp_audiosrv_set_hotplug_cb (pdata -> dcp_dev , dev , dcpaud_report_hotplug );
575-
576589 return 0 ;
577590
578591err_free_card :
579592 snd_card_free (dcpaud -> card );
580593 return ret ;
581594}
582595
583- static int dcpaud_remove (struct platform_device * dev )
596+ static void dcpaud_comp_unbind (struct device * dev , struct device * main ,
597+ void * data )
584598{
585- struct dcp_audio * dcpaud = platform_get_drvdata (dev );
599+ struct dcp_audio * dcpaud = dev_get_drvdata (dev );
586600
587- dcp_audiosrv_set_hotplug_cb (dcpaud -> pdata -> dcp_dev , NULL , NULL );
588601 snd_card_free (dcpaud -> card );
602+ }
603+
604+ static const struct component_ops dcpaud_comp_ops = {
605+ .bind = dcpaud_comp_bind ,
606+ .unbind = dcpaud_comp_unbind ,
607+ };
608+
609+ static int dcpaud_probe (struct platform_device * pdev )
610+ {
611+ struct dcp_audio * dcpaud ;
612+
613+ dcpaud = devm_kzalloc (& pdev -> dev , sizeof (* dcpaud ), GFP_KERNEL );
614+ if (!dcpaud )
615+ return - ENOMEM ;
616+
617+ dcpaud -> elements = devm_kzalloc (& pdev -> dev , DCPAUD_ELEMENTS_MAXSIZE ,
618+ GFP_KERNEL );
619+ if (!dcpaud -> elements )
620+ return - ENOMEM ;
621+
622+ dcpaud -> productattrs = devm_kzalloc (& pdev -> dev , DCPAUD_PRODUCTATTRS_MAXSIZE ,
623+ GFP_KERNEL );
624+ if (!dcpaud -> productattrs )
625+ return - ENOMEM ;
626+
627+ dcpaud -> dev = & pdev -> dev ;
628+ mutex_init (& dcpaud -> data_lock );
629+ platform_set_drvdata (pdev , dcpaud );
630+
631+ return component_add (& pdev -> dev , & dcpaud_comp_ops );
632+ }
633+
634+ static int dcpaud_remove (struct platform_device * pdev )
635+ {
636+ component_del (& pdev -> dev , & dcpaud_comp_ops );
589637
590638 return 0 ;
591639}
592640
641+ static void dcpaud_shutdown (struct platform_device * pdev )
642+ {
643+ component_del (& pdev -> dev , & dcpaud_comp_ops );
644+ }
645+
646+ // static DEFINE_SIMPLE_DEV_PM_OPS(dcpaud_pm_ops, dcpaud_suspend, dcpaud_resume);
647+
648+ static const struct of_device_id dcpaud_of_match [] = {
649+ { .compatible = "apple,dpaudio" },
650+ {}
651+ };
652+
593653static struct platform_driver dcpaud_driver = {
594654 .driver = {
595- .name = DRV_NAME ,
655+ .name = "dcp-dp-audio" ,
656+ .of_match_table = dcpaud_of_match ,
596657 },
597- .probe = dcpaud_probe ,
598- .remove = dcpaud_remove ,
658+ .probe = dcpaud_probe ,
659+ .remove = dcpaud_remove ,
660+ .shutdown = dcpaud_shutdown ,
599661};
600662
601663void __init dcp_audio_register (void )
0 commit comments