16
16
#include <linux/pci.h>
17
17
#include <linux/module.h>
18
18
#include <linux/io.h>
19
+ #include <linux/platform_device.h>
20
+ #include <linux/interrupt.h>
19
21
20
22
#include "acp3x.h"
21
23
22
24
struct acp3x_dev_data {
23
25
void __iomem * acp3x_base ;
26
+ bool acp3x_audio_mode ;
27
+ struct resource * res ;
28
+ struct platform_device * pdev ;
24
29
};
25
30
26
31
static int snd_acp3x_probe (struct pci_dev * pci ,
27
32
const struct pci_device_id * pci_id )
28
33
{
29
34
int ret ;
30
- u32 addr ;
35
+ u32 addr , val ;
31
36
struct acp3x_dev_data * adata ;
37
+ struct platform_device_info pdevinfo ;
38
+ unsigned int irqflags ;
32
39
33
40
if (pci_enable_device (pci )) {
34
41
dev_err (& pci -> dev , "pci_enable_device failed\n" );
@@ -48,6 +55,15 @@ static int snd_acp3x_probe(struct pci_dev *pci,
48
55
goto release_regions ;
49
56
}
50
57
58
+ /* check for msi interrupt support */
59
+ ret = pci_enable_msi (pci );
60
+ if (ret )
61
+ /* msi is not enabled */
62
+ irqflags = IRQF_SHARED ;
63
+ else
64
+ /* msi is enabled */
65
+ irqflags = 0 ;
66
+
51
67
addr = pci_resource_start (pci , 0 );
52
68
adata -> acp3x_base = ioremap (addr , pci_resource_len (pci , 0 ));
53
69
if (!adata -> acp3x_base ) {
@@ -56,8 +72,57 @@ static int snd_acp3x_probe(struct pci_dev *pci,
56
72
}
57
73
pci_set_master (pci );
58
74
pci_set_drvdata (pci , adata );
75
+
76
+ val = rv_readl (adata -> acp3x_base + mmACP_I2S_PIN_CONFIG );
77
+ switch (val ) {
78
+ case I2S_MODE :
79
+ adata -> res = devm_kzalloc (& pci -> dev ,
80
+ sizeof (struct resource ) * 2 ,
81
+ GFP_KERNEL );
82
+ if (!adata -> res ) {
83
+ ret = - ENOMEM ;
84
+ goto unmap_mmio ;
85
+ }
86
+
87
+ adata -> res [0 ].name = "acp3x_i2s_iomem" ;
88
+ adata -> res [0 ].flags = IORESOURCE_MEM ;
89
+ adata -> res [0 ].start = addr ;
90
+ adata -> res [0 ].end = addr + (ACP3x_REG_END - ACP3x_REG_START );
91
+
92
+ adata -> res [1 ].name = "acp3x_i2s_irq" ;
93
+ adata -> res [1 ].flags = IORESOURCE_IRQ ;
94
+ adata -> res [1 ].start = pci -> irq ;
95
+ adata -> res [1 ].end = pci -> irq ;
96
+
97
+ adata -> acp3x_audio_mode = ACP3x_I2S_MODE ;
98
+
99
+ memset (& pdevinfo , 0 , sizeof (pdevinfo ));
100
+ pdevinfo .name = "acp3x_rv_i2s" ;
101
+ pdevinfo .id = 0 ;
102
+ pdevinfo .parent = & pci -> dev ;
103
+ pdevinfo .num_res = 2 ;
104
+ pdevinfo .res = adata -> res ;
105
+ pdevinfo .data = & irqflags ;
106
+ pdevinfo .size_data = sizeof (irqflags );
107
+
108
+ adata -> pdev = platform_device_register_full (& pdevinfo );
109
+ if (!adata -> pdev ) {
110
+ dev_err (& pci -> dev , "cannot register %s device\n" ,
111
+ pdevinfo .name );
112
+ ret = - ENODEV ;
113
+ goto unmap_mmio ;
114
+ }
115
+ break ;
116
+ default :
117
+ dev_err (& pci -> dev , "Inavlid ACP audio mode : %d\n" , val );
118
+ ret = - ENODEV ;
119
+ goto unmap_mmio ;
120
+ }
59
121
return 0 ;
60
122
123
+ unmap_mmio :
124
+ pci_disable_msi (pci );
125
+ iounmap (adata -> acp3x_base );
61
126
release_regions :
62
127
pci_release_regions (pci );
63
128
disable_pci :
@@ -70,7 +135,10 @@ static void snd_acp3x_remove(struct pci_dev *pci)
70
135
{
71
136
struct acp3x_dev_data * adata = pci_get_drvdata (pci );
72
137
138
+ platform_device_unregister (adata -> pdev );
73
139
iounmap (adata -> acp3x_base );
140
+
141
+ pci_disable_msi (pci );
74
142
pci_release_regions (pci );
75
143
pci_disable_device (pci );
76
144
}
0 commit comments