Skip to content

Commit 8fcc7ab

Browse files
committed
drm: apple: audio: Make the DP/HDMI audio driver a full driver
The main advantage is that it allows runtime PM which would have been manually implemented with the ad-hoc instantiated platform driver. This also probes the devices as component of the DRM driver which allows to simplify the the interface between the av endpoint and the audio driver. Signed-off-by: Janne Grunau <[email protected]>
1 parent bd1c2aa commit 8fcc7ab

4 files changed

Lines changed: 155 additions & 97 deletions

File tree

drivers/gpu/drm/apple/apple_drv.c

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <linux/module.h>
1515
#include <linux/of_address.h>
1616
#include <linux/of_device.h>
17+
#include <linux/of_graph.h>
1718
#include <linux/of_platform.h>
1819

1920
#include <drm/drm_aperture.h>
@@ -574,14 +575,31 @@ const struct component_master_ops apple_drm_ops = {
574575
static int add_dcp_components(struct device *dev,
575576
struct component_match **matchptr)
576577
{
577-
struct device_node *np;
578+
struct device_node *np, *endpoint, *port;
578579
int num = 0;
579580

580581
for_each_matching_node(np, apple_dcp_id_tbl) {
581582
if (of_device_is_available(np)) {
582583
drm_of_component_match_add(dev, matchptr,
583584
component_compare_of, np);
584585
num++;
586+
for_each_endpoint_of_node(np, endpoint) {
587+
port = of_graph_get_remote_port_parent(endpoint);
588+
if (!port)
589+
continue;
590+
591+
#if !IS_ENABLED(CONFIG_DRM_APPLE_AUDIO)
592+
if (of_device_is_compatible(port, "apple,dpaudio")) {
593+
of_node_put(port);
594+
continue;
595+
}
596+
#endif
597+
if (of_device_is_available(port))
598+
drm_of_component_match_add(dev, matchptr,
599+
component_compare_of,
600+
port);
601+
of_node_put(port);
602+
}
585603
}
586604
of_node_put(np);
587605
}

drivers/gpu/drm/apple/audio.c

Lines changed: 104 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,12 @@
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>
@@ -22,17 +25,16 @@
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-
3335
struct 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

323325
static 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
516517
static 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

578591
err_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+
593653
static 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

601663
void __init dcp_audio_register(void)

drivers/gpu/drm/apple/audio.h

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,17 @@
44
#include <linux/types.h>
55

66
struct device;
7-
struct device_node;
7+
struct platform_device;
88
struct dcp_sound_cookie;
99

10-
typedef void (*dcp_audio_hotplug_callback)(struct device *dev, bool connected);
11-
12-
struct dcp_audio_pdata {
13-
struct device *dcp_dev;
14-
struct device_node *dpaudio_node;
15-
};
16-
17-
void dcp_audiosrv_set_hotplug_cb(struct device *dev, struct device *audio_dev,
18-
dcp_audio_hotplug_callback cb);
1910
int dcp_audiosrv_prepare(struct device *dev, struct dcp_sound_cookie *cookie);
2011
int dcp_audiosrv_startlink(struct device *dev, struct dcp_sound_cookie *cookie);
2112
int dcp_audiosrv_stoplink(struct device *dev);
2213
int dcp_audiosrv_unprepare(struct device *dev);
2314
int dcp_audiosrv_get_elements(struct device *dev, void *elements, size_t maxsize);
2415
int dcp_audiosrv_get_product_attrs(struct device *dev, void *attrs, size_t maxsize);
2516

17+
void dcpaud_connect(struct platform_device *pdev, bool connected);
18+
void dcpaud_disconnect(struct platform_device *pdev);
19+
2620
#endif /* __AUDIO_H__ */

0 commit comments

Comments
 (0)