aboutsummaryrefslogtreecommitdiffstats
path: root/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71/1101-ASoC-AMD-create-ACP3x-PCM-platform-device.patch
blob: 68ea87a1bea41fbb3d4765fc15e5389b725e7b33 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
From 5de6a6c59f338b72cf60c084126fdb69e4ab32b7 Mon Sep 17 00:00:00 2001
From: Maruthi Srinivas Bayyavarapu <Maruthi.Bayyavarapu@amd.com>
Date: Wed, 29 Mar 2017 18:34:38 +0530
Subject: [PATCH 1101/4131] ASoC: AMD: create ACP3x PCM platform device

ACP 3x IP have I2S controller device as one of IP blocks.
Create a platform device for it, so that PCM platform driver
can be binded to this device. Pass PCI resources like MMIO, irq
to the platform device.

Signed-off-by: Maruthi Bayyavarapu <maruthi.bayyavarapu@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 sound/soc/amd/raven/acp3x.h     |  3 ++
 sound/soc/amd/raven/pci-acp3x.c | 68 ++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 70 insertions(+), 1 deletion(-)

diff --git a/sound/soc/amd/raven/acp3x.h b/sound/soc/amd/raven/acp3x.h
index e9b4df0..1996faf 100644
--- a/sound/soc/amd/raven/acp3x.h
+++ b/sound/soc/amd/raven/acp3x.h
@@ -1,6 +1,9 @@
 #include "chip_offset_byte.h"
 
 #define ACP3x_PHY_BASE_ADDRESS 0x1240000
+#define	ACP3x_I2S_MODE	0
+#define	ACP3x_REG_START	0x1240000
+#define	ACP3x_REG_END	0x1250200
 
 static inline u32 rv_readl(void __iomem *base_addr)
 {
diff --git a/sound/soc/amd/raven/pci-acp3x.c b/sound/soc/amd/raven/pci-acp3x.c
index 204212b..a182013 100644
--- a/sound/soc/amd/raven/pci-acp3x.c
+++ b/sound/soc/amd/raven/pci-acp3x.c
@@ -15,19 +15,26 @@
 
 #include <linux/pci.h>
 #include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
 
 #include "acp3x.h"
 
 struct acp3x_dev_data {
 	void __iomem *acp3x_base;
+	bool acp3x_audio_mode;
+	struct resource *res;
+	struct platform_device *pdev;
 };
 
 static int snd_acp3x_probe(struct pci_dev *pci,
 			   const struct pci_device_id *pci_id)
 {
 	int ret;
-	u32 addr;
+	u32 addr, val;
 	struct acp3x_dev_data *adata;
+	struct platform_device_info pdevinfo;
+	unsigned int irqflags;
 
 	if (pci_enable_device(pci)) {
 		dev_err(&pci->dev, "pci_enable_device failed\n");
@@ -47,6 +54,15 @@ static int snd_acp3x_probe(struct pci_dev *pci,
 		goto release_regions;
 	}
 
+	/* check for msi interrupt support */
+	ret = pci_enable_msi(pci);
+	if (ret)
+		/* msi is not enabled */
+		irqflags = IRQF_SHARED;
+	else
+		/* msi is enabled */
+		irqflags = 0;
+
 	addr = pci_resource_start(pci, 0);
 	adata->acp3x_base = ioremap(addr, pci_resource_len(pci, 0));
 	if (adata->acp3x_base == NULL) {
@@ -56,8 +72,55 @@ static int snd_acp3x_probe(struct pci_dev *pci,
 
 	pci_set_drvdata(pci, adata);
 
+	val = rv_readl(adata->acp3x_base + mmACP_I2S_PIN_CONFIG);
+	if (val == 0x4) {
+		adata->res = devm_kzalloc(&pci->dev,
+				sizeof(struct resource) * 2,
+				GFP_KERNEL);
+		if (adata->res == NULL) {
+			ret = -ENOMEM;
+			goto unmap_mmio;
+		}
+
+		adata->res[0].name = "acp3x_i2s_iomem";
+		adata->res[0].flags = IORESOURCE_MEM;
+		adata->res[0].start = addr;
+		adata->res[0].end = addr + (ACP3x_REG_END - ACP3x_REG_START);
+
+		adata->res[1].name = "acp3x_i2s_irq";
+		adata->res[1].flags = IORESOURCE_IRQ;
+		adata->res[1].start = pci->irq;
+		adata->res[1].end = pci->irq;
+
+		adata->acp3x_audio_mode = ACP3x_I2S_MODE;
+
+		memset(&pdevinfo, 0, sizeof(pdevinfo));
+		pdevinfo.name = "acp3x_rv_i2s";
+		pdevinfo.id = 0;
+		pdevinfo.parent = &pci->dev;
+		pdevinfo.num_res = 2;
+		pdevinfo.res = adata->res;
+		pdevinfo.data = &irqflags;
+		pdevinfo.size_data = sizeof(irqflags);
+
+		adata->pdev = platform_device_register_full(&pdevinfo);
+		if (adata->pdev == NULL) {
+			dev_err(&pci->dev, "cannot register %s device\n",
+				pdevinfo.name);
+			ret = -ENODEV;
+			goto unmap_mmio;
+		}
+	} else {
+		dev_err(&pci->dev, "Inavlid ACP audio mode : %d\n", val);
+		ret = -ENODEV;
+		goto unmap_mmio;
+	}
+
 	return 0;
 
+unmap_mmio:
+	pci_disable_msi(pci);
+	iounmap(adata->acp3x_base);
 release_regions:
 	pci_release_regions(pci);
 disable_pci:
@@ -70,7 +133,10 @@ static void snd_acp3x_remove(struct pci_dev *pci)
 {
 	struct acp3x_dev_data *adata = pci_get_drvdata(pci);
 
+	platform_device_unregister(adata->pdev);
 	iounmap(adata->acp3x_base);
+
+	pci_disable_msi(pci);
 	pci_release_regions(pci);
 	pci_disable_device(pci);
 }
-- 
2.7.4