1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | Hopper PCI bridge driver |
4 | |
5 | Copyright (C) Manu Abraham (abraham.manu@gmail.com) |
6 | |
7 | */ |
8 | |
9 | #include <linux/module.h> |
10 | #include <linux/moduleparam.h> |
11 | #include <linux/kernel.h> |
12 | #include <linux/pci.h> |
13 | #include <linux/slab.h> |
14 | #include <asm/irq.h> |
15 | #include <linux/interrupt.h> |
16 | |
17 | #include <media/dmxdev.h> |
18 | #include <media/dvbdev.h> |
19 | #include <media/dvb_demux.h> |
20 | #include <media/dvb_frontend.h> |
21 | #include <media/dvb_net.h> |
22 | |
23 | #include "mantis_common.h" |
24 | #include "hopper_vp3028.h" |
25 | #include "mantis_dma.h" |
26 | #include "mantis_dvb.h" |
27 | #include "mantis_uart.h" |
28 | #include "mantis_ioc.h" |
29 | #include "mantis_pci.h" |
30 | #include "mantis_i2c.h" |
31 | #include "mantis_reg.h" |
32 | |
33 | static unsigned int verbose; |
34 | module_param(verbose, int, 0644); |
35 | MODULE_PARM_DESC(verbose, "verbose startup messages, default is 0 (no)" ); |
36 | |
37 | #define DRIVER_NAME "Hopper" |
38 | |
39 | static char *label[10] = { |
40 | "DMA" , |
41 | "IRQ-0" , |
42 | "IRQ-1" , |
43 | "OCERR" , |
44 | "PABRT" , |
45 | "RIPRR" , |
46 | "PPERR" , |
47 | "FTRGT" , |
48 | "RISCI" , |
49 | "RACK" |
50 | }; |
51 | |
52 | static int devs; |
53 | |
54 | static irqreturn_t hopper_irq_handler(int irq, void *dev_id) |
55 | { |
56 | u32 stat = 0, mask = 0; |
57 | u32 rst_stat = 0, rst_mask = 0; |
58 | |
59 | struct mantis_pci *mantis; |
60 | struct mantis_ca *ca; |
61 | |
62 | mantis = (struct mantis_pci *) dev_id; |
63 | if (unlikely(!mantis)) |
64 | return IRQ_NONE; |
65 | ca = mantis->mantis_ca; |
66 | |
67 | stat = mmread(MANTIS_INT_STAT); |
68 | mask = mmread(MANTIS_INT_MASK); |
69 | if (!(stat & mask)) |
70 | return IRQ_NONE; |
71 | |
72 | rst_mask = MANTIS_GPIF_WRACK | |
73 | MANTIS_GPIF_OTHERR | |
74 | MANTIS_SBUF_WSTO | |
75 | MANTIS_GPIF_EXTIRQ; |
76 | |
77 | rst_stat = mmread(MANTIS_GPIF_STATUS); |
78 | rst_stat &= rst_mask; |
79 | mmwrite(rst_stat, MANTIS_GPIF_STATUS); |
80 | |
81 | mantis->mantis_int_stat = stat; |
82 | mantis->mantis_int_mask = mask; |
83 | dprintk(MANTIS_DEBUG, 0, "\n-- Stat=<%02x> Mask=<%02x> --" , stat, mask); |
84 | if (stat & MANTIS_INT_RISCEN) { |
85 | dprintk(MANTIS_DEBUG, 0, "<%s>" , label[0]); |
86 | } |
87 | if (stat & MANTIS_INT_IRQ0) { |
88 | dprintk(MANTIS_DEBUG, 0, "<%s>" , label[1]); |
89 | mantis->gpif_status = rst_stat; |
90 | wake_up(&ca->hif_write_wq); |
91 | schedule_work(work: &ca->hif_evm_work); |
92 | } |
93 | if (stat & MANTIS_INT_IRQ1) { |
94 | dprintk(MANTIS_DEBUG, 0, "<%s>" , label[2]); |
95 | spin_lock(lock: &mantis->intmask_lock); |
96 | mmwrite(mmread(MANTIS_INT_MASK) & ~MANTIS_INT_IRQ1, |
97 | MANTIS_INT_MASK); |
98 | spin_unlock(lock: &mantis->intmask_lock); |
99 | schedule_work(work: &mantis->uart_work); |
100 | } |
101 | if (stat & MANTIS_INT_OCERR) { |
102 | dprintk(MANTIS_DEBUG, 0, "<%s>" , label[3]); |
103 | } |
104 | if (stat & MANTIS_INT_PABORT) { |
105 | dprintk(MANTIS_DEBUG, 0, "<%s>" , label[4]); |
106 | } |
107 | if (stat & MANTIS_INT_RIPERR) { |
108 | dprintk(MANTIS_DEBUG, 0, "<%s>" , label[5]); |
109 | } |
110 | if (stat & MANTIS_INT_PPERR) { |
111 | dprintk(MANTIS_DEBUG, 0, "<%s>" , label[6]); |
112 | } |
113 | if (stat & MANTIS_INT_FTRGT) { |
114 | dprintk(MANTIS_DEBUG, 0, "<%s>" , label[7]); |
115 | } |
116 | if (stat & MANTIS_INT_RISCI) { |
117 | dprintk(MANTIS_DEBUG, 0, "<%s>" , label[8]); |
118 | mantis->busy_block = (stat & MANTIS_INT_RISCSTAT) >> 28; |
119 | tasklet_schedule(t: &mantis->tasklet); |
120 | } |
121 | if (stat & MANTIS_INT_I2CDONE) { |
122 | dprintk(MANTIS_DEBUG, 0, "<%s>" , label[9]); |
123 | wake_up(&mantis->i2c_wq); |
124 | } |
125 | mmwrite(stat, MANTIS_INT_STAT); |
126 | stat &= ~(MANTIS_INT_RISCEN | MANTIS_INT_I2CDONE | |
127 | MANTIS_INT_I2CRACK | MANTIS_INT_PCMCIA7 | |
128 | MANTIS_INT_PCMCIA6 | MANTIS_INT_PCMCIA5 | |
129 | MANTIS_INT_PCMCIA4 | MANTIS_INT_PCMCIA3 | |
130 | MANTIS_INT_PCMCIA2 | MANTIS_INT_PCMCIA1 | |
131 | MANTIS_INT_PCMCIA0 | MANTIS_INT_IRQ1 | |
132 | MANTIS_INT_IRQ0 | MANTIS_INT_OCERR | |
133 | MANTIS_INT_PABORT | MANTIS_INT_RIPERR | |
134 | MANTIS_INT_PPERR | MANTIS_INT_FTRGT | |
135 | MANTIS_INT_RISCI); |
136 | |
137 | if (stat) |
138 | dprintk(MANTIS_DEBUG, 0, "<Unknown> Stat=<%02x> Mask=<%02x>" , stat, mask); |
139 | |
140 | dprintk(MANTIS_DEBUG, 0, "\n" ); |
141 | return IRQ_HANDLED; |
142 | } |
143 | |
144 | static int hopper_pci_probe(struct pci_dev *pdev, |
145 | const struct pci_device_id *pci_id) |
146 | { |
147 | struct mantis_pci_drvdata *drvdata; |
148 | struct mantis_pci *mantis; |
149 | struct mantis_hwconfig *config; |
150 | int err; |
151 | |
152 | mantis = kzalloc(size: sizeof(*mantis), GFP_KERNEL); |
153 | if (!mantis) { |
154 | err = -ENOMEM; |
155 | goto fail0; |
156 | } |
157 | |
158 | drvdata = (void *)pci_id->driver_data; |
159 | mantis->num = devs; |
160 | mantis->verbose = verbose; |
161 | mantis->pdev = pdev; |
162 | config = drvdata->hwconfig; |
163 | config->irq_handler = &hopper_irq_handler; |
164 | mantis->hwconfig = config; |
165 | mantis->rc_map_name = drvdata->rc_map_name; |
166 | |
167 | spin_lock_init(&mantis->intmask_lock); |
168 | |
169 | err = mantis_pci_init(mantis); |
170 | if (err) { |
171 | dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI initialization failed <%d>" , err); |
172 | goto fail1; |
173 | } |
174 | |
175 | err = mantis_stream_control(mantis, stream_ctl: STREAM_TO_HIF); |
176 | if (err < 0) { |
177 | dprintk(MANTIS_ERROR, 1, "ERROR: Mantis stream control failed <%d>" , err); |
178 | goto fail1; |
179 | } |
180 | |
181 | err = mantis_i2c_init(mantis); |
182 | if (err < 0) { |
183 | dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C initialization failed <%d>" , err); |
184 | goto fail2; |
185 | } |
186 | |
187 | err = mantis_get_mac(mantis); |
188 | if (err < 0) { |
189 | dprintk(MANTIS_ERROR, 1, "ERROR: Mantis MAC address read failed <%d>" , err); |
190 | goto fail2; |
191 | } |
192 | |
193 | err = mantis_dma_init(mantis); |
194 | if (err < 0) { |
195 | dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA initialization failed <%d>" , err); |
196 | goto fail3; |
197 | } |
198 | |
199 | err = mantis_dvb_init(mantis); |
200 | if (err < 0) { |
201 | dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DVB initialization failed <%d>" , err); |
202 | goto fail4; |
203 | } |
204 | devs++; |
205 | |
206 | return err; |
207 | |
208 | fail4: |
209 | dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA exit! <%d>" , err); |
210 | mantis_dma_exit(mantis); |
211 | |
212 | fail3: |
213 | dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C exit! <%d>" , err); |
214 | mantis_i2c_exit(mantis); |
215 | |
216 | fail2: |
217 | dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI exit! <%d>" , err); |
218 | mantis_pci_exit(mantis); |
219 | |
220 | fail1: |
221 | dprintk(MANTIS_ERROR, 1, "ERROR: Mantis free! <%d>" , err); |
222 | kfree(objp: mantis); |
223 | |
224 | fail0: |
225 | return err; |
226 | } |
227 | |
228 | static void hopper_pci_remove(struct pci_dev *pdev) |
229 | { |
230 | struct mantis_pci *mantis = pci_get_drvdata(pdev); |
231 | |
232 | if (mantis) { |
233 | mantis_dvb_exit(mantis); |
234 | mantis_dma_exit(mantis); |
235 | mantis_i2c_exit(mantis); |
236 | mantis_pci_exit(mantis); |
237 | kfree(objp: mantis); |
238 | } |
239 | return; |
240 | |
241 | } |
242 | |
243 | static const struct pci_device_id hopper_pci_table[] = { |
244 | MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3028_DVB_T, &vp3028_config, |
245 | NULL), |
246 | { } |
247 | }; |
248 | |
249 | MODULE_DEVICE_TABLE(pci, hopper_pci_table); |
250 | |
251 | static struct pci_driver hopper_pci_driver = { |
252 | .name = DRIVER_NAME, |
253 | .id_table = hopper_pci_table, |
254 | .probe = hopper_pci_probe, |
255 | .remove = hopper_pci_remove, |
256 | }; |
257 | |
258 | module_pci_driver(hopper_pci_driver); |
259 | |
260 | MODULE_DESCRIPTION("HOPPER driver" ); |
261 | MODULE_AUTHOR("Manu Abraham" ); |
262 | MODULE_LICENSE("GPL" ); |
263 | |