Skip to content

Commit 946fcad

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 <j@jannau.net>
1 parent de23abd commit 946fcad

4 files changed

Lines changed: 155 additions & 99 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: 105 additions & 44 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;
@@ -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
518519
static 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

580593
err_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+
595654
static 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

603664
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)