1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | Mantis PCI bridge driver |
4 | |
5 | Copyright (C) Manu Abraham (abraham.manu@gmail.com) |
6 | |
7 | */ |
8 | |
9 | #include <linux/module.h> |
10 | #include <linux/kernel.h> |
11 | #include <linux/pci.h> |
12 | #include <linux/slab.h> |
13 | #include <asm/irq.h> |
14 | #include <linux/interrupt.h> |
15 | #include <media/rc-map.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 | |
25 | #include "mantis_vp1033.h" |
26 | #include "mantis_vp1034.h" |
27 | #include "mantis_vp1041.h" |
28 | #include "mantis_vp2033.h" |
29 | #include "mantis_vp2040.h" |
30 | #include "mantis_vp3030.h" |
31 | |
32 | #include "mantis_dma.h" |
33 | #include "mantis_ca.h" |
34 | #include "mantis_dvb.h" |
35 | #include "mantis_uart.h" |
36 | #include "mantis_ioc.h" |
37 | #include "mantis_pci.h" |
38 | #include "mantis_i2c.h" |
39 | #include "mantis_reg.h" |
40 | #include "mantis_input.h" |
41 | |
42 | static unsigned int verbose; |
43 | module_param(verbose, int, 0644); |
44 | MODULE_PARM_DESC(verbose, "verbose startup messages, default is 0 (no)" ); |
45 | |
46 | static int devs; |
47 | |
48 | #define DRIVER_NAME "Mantis" |
49 | |
50 | static char *label[10] = { |
51 | "DMA" , |
52 | "IRQ-0" , |
53 | "IRQ-1" , |
54 | "OCERR" , |
55 | "PABRT" , |
56 | "RIPRR" , |
57 | "PPERR" , |
58 | "FTRGT" , |
59 | "RISCI" , |
60 | "RACK" |
61 | }; |
62 | |
63 | static irqreturn_t mantis_irq_handler(int irq, void *dev_id) |
64 | { |
65 | u32 stat = 0, mask = 0; |
66 | u32 rst_stat = 0, rst_mask = 0; |
67 | |
68 | struct mantis_pci *mantis; |
69 | struct mantis_ca *ca; |
70 | |
71 | mantis = (struct mantis_pci *) dev_id; |
72 | if (unlikely(!mantis)) |
73 | return IRQ_NONE; |
74 | ca = mantis->mantis_ca; |
75 | |
76 | stat = mmread(MANTIS_INT_STAT); |
77 | mask = mmread(MANTIS_INT_MASK); |
78 | if (!(stat & mask)) |
79 | return IRQ_NONE; |
80 | |
81 | rst_mask = MANTIS_GPIF_WRACK | |
82 | MANTIS_GPIF_OTHERR | |
83 | MANTIS_SBUF_WSTO | |
84 | MANTIS_GPIF_EXTIRQ; |
85 | |
86 | rst_stat = mmread(MANTIS_GPIF_STATUS); |
87 | rst_stat &= rst_mask; |
88 | mmwrite(rst_stat, MANTIS_GPIF_STATUS); |
89 | |
90 | mantis->mantis_int_stat = stat; |
91 | mantis->mantis_int_mask = mask; |
92 | dprintk(MANTIS_DEBUG, 0, "\n-- Stat=<%02x> Mask=<%02x> --" , stat, mask); |
93 | if (stat & MANTIS_INT_RISCEN) { |
94 | dprintk(MANTIS_DEBUG, 0, "<%s>" , label[0]); |
95 | } |
96 | if (stat & MANTIS_INT_IRQ0) { |
97 | dprintk(MANTIS_DEBUG, 0, "<%s>" , label[1]); |
98 | mantis->gpif_status = rst_stat; |
99 | wake_up(&ca->hif_write_wq); |
100 | schedule_work(work: &ca->hif_evm_work); |
101 | } |
102 | if (stat & MANTIS_INT_IRQ1) { |
103 | dprintk(MANTIS_DEBUG, 0, "<%s>" , label[2]); |
104 | spin_lock(lock: &mantis->intmask_lock); |
105 | mmwrite(mmread(MANTIS_INT_MASK) & ~MANTIS_INT_IRQ1, |
106 | MANTIS_INT_MASK); |
107 | spin_unlock(lock: &mantis->intmask_lock); |
108 | schedule_work(work: &mantis->uart_work); |
109 | } |
110 | if (stat & MANTIS_INT_OCERR) { |
111 | dprintk(MANTIS_DEBUG, 0, "<%s>" , label[3]); |
112 | } |
113 | if (stat & MANTIS_INT_PABORT) { |
114 | dprintk(MANTIS_DEBUG, 0, "<%s>" , label[4]); |
115 | } |
116 | if (stat & MANTIS_INT_RIPERR) { |
117 | dprintk(MANTIS_DEBUG, 0, "<%s>" , label[5]); |
118 | } |
119 | if (stat & MANTIS_INT_PPERR) { |
120 | dprintk(MANTIS_DEBUG, 0, "<%s>" , label[6]); |
121 | } |
122 | if (stat & MANTIS_INT_FTRGT) { |
123 | dprintk(MANTIS_DEBUG, 0, "<%s>" , label[7]); |
124 | } |
125 | if (stat & MANTIS_INT_RISCI) { |
126 | dprintk(MANTIS_DEBUG, 0, "<%s>" , label[8]); |
127 | mantis->busy_block = (stat & MANTIS_INT_RISCSTAT) >> 28; |
128 | tasklet_schedule(t: &mantis->tasklet); |
129 | } |
130 | if (stat & MANTIS_INT_I2CDONE) { |
131 | dprintk(MANTIS_DEBUG, 0, "<%s>" , label[9]); |
132 | wake_up(&mantis->i2c_wq); |
133 | } |
134 | mmwrite(stat, MANTIS_INT_STAT); |
135 | stat &= ~(MANTIS_INT_RISCEN | MANTIS_INT_I2CDONE | |
136 | MANTIS_INT_I2CRACK | MANTIS_INT_PCMCIA7 | |
137 | MANTIS_INT_PCMCIA6 | MANTIS_INT_PCMCIA5 | |
138 | MANTIS_INT_PCMCIA4 | MANTIS_INT_PCMCIA3 | |
139 | MANTIS_INT_PCMCIA2 | MANTIS_INT_PCMCIA1 | |
140 | MANTIS_INT_PCMCIA0 | MANTIS_INT_IRQ1 | |
141 | MANTIS_INT_IRQ0 | MANTIS_INT_OCERR | |
142 | MANTIS_INT_PABORT | MANTIS_INT_RIPERR | |
143 | MANTIS_INT_PPERR | MANTIS_INT_FTRGT | |
144 | MANTIS_INT_RISCI); |
145 | |
146 | if (stat) |
147 | dprintk(MANTIS_DEBUG, 0, "<Unknown> Stat=<%02x> Mask=<%02x>" , stat, mask); |
148 | |
149 | dprintk(MANTIS_DEBUG, 0, "\n" ); |
150 | return IRQ_HANDLED; |
151 | } |
152 | |
153 | static int mantis_pci_probe(struct pci_dev *pdev, |
154 | const struct pci_device_id *pci_id) |
155 | { |
156 | struct mantis_pci_drvdata *drvdata; |
157 | struct mantis_pci *mantis; |
158 | struct mantis_hwconfig *config; |
159 | int err; |
160 | |
161 | mantis = kzalloc(size: sizeof(*mantis), GFP_KERNEL); |
162 | if (!mantis) |
163 | return -ENOMEM; |
164 | |
165 | drvdata = (void *)pci_id->driver_data; |
166 | mantis->num = devs; |
167 | mantis->verbose = verbose; |
168 | mantis->pdev = pdev; |
169 | config = drvdata->hwconfig; |
170 | config->irq_handler = &mantis_irq_handler; |
171 | mantis->hwconfig = config; |
172 | mantis->rc_map_name = drvdata->rc_map_name; |
173 | |
174 | spin_lock_init(&mantis->intmask_lock); |
175 | |
176 | err = mantis_pci_init(mantis); |
177 | if (err) { |
178 | dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI initialization failed <%d>" , err); |
179 | goto err_free_mantis; |
180 | } |
181 | |
182 | err = mantis_stream_control(mantis, stream_ctl: STREAM_TO_HIF); |
183 | if (err < 0) { |
184 | dprintk(MANTIS_ERROR, 1, "ERROR: Mantis stream control failed <%d>" , err); |
185 | goto err_pci_exit; |
186 | } |
187 | |
188 | err = mantis_i2c_init(mantis); |
189 | if (err < 0) { |
190 | dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C initialization failed <%d>" , err); |
191 | goto err_pci_exit; |
192 | } |
193 | |
194 | err = mantis_get_mac(mantis); |
195 | if (err < 0) { |
196 | dprintk(MANTIS_ERROR, 1, "ERROR: Mantis MAC address read failed <%d>" , err); |
197 | goto err_i2c_exit; |
198 | } |
199 | |
200 | err = mantis_dma_init(mantis); |
201 | if (err < 0) { |
202 | dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA initialization failed <%d>" , err); |
203 | goto err_i2c_exit; |
204 | } |
205 | |
206 | err = mantis_dvb_init(mantis); |
207 | if (err < 0) { |
208 | dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DVB initialization failed <%d>" , err); |
209 | goto err_dma_exit; |
210 | } |
211 | |
212 | err = mantis_input_init(mantis); |
213 | if (err < 0) { |
214 | dprintk(MANTIS_ERROR, 1, |
215 | "ERROR: Mantis DVB initialization failed <%d>" , err); |
216 | goto err_dvb_exit; |
217 | } |
218 | |
219 | err = mantis_uart_init(mantis); |
220 | if (err < 0) { |
221 | dprintk(MANTIS_ERROR, 1, "ERROR: Mantis UART initialization failed <%d>" , err); |
222 | goto err_input_exit; |
223 | } |
224 | |
225 | devs++; |
226 | |
227 | return 0; |
228 | |
229 | err_input_exit: |
230 | mantis_input_exit(mantis); |
231 | |
232 | err_dvb_exit: |
233 | mantis_dvb_exit(mantis); |
234 | |
235 | err_dma_exit: |
236 | mantis_dma_exit(mantis); |
237 | |
238 | err_i2c_exit: |
239 | mantis_i2c_exit(mantis); |
240 | |
241 | err_pci_exit: |
242 | mantis_pci_exit(mantis); |
243 | |
244 | err_free_mantis: |
245 | kfree(objp: mantis); |
246 | |
247 | return err; |
248 | } |
249 | |
250 | static void mantis_pci_remove(struct pci_dev *pdev) |
251 | { |
252 | struct mantis_pci *mantis = pci_get_drvdata(pdev); |
253 | |
254 | if (mantis) { |
255 | |
256 | mantis_uart_exit(mantis); |
257 | mantis_input_exit(mantis); |
258 | mantis_dvb_exit(mantis); |
259 | mantis_dma_exit(mantis); |
260 | mantis_i2c_exit(mantis); |
261 | mantis_pci_exit(mantis); |
262 | kfree(objp: mantis); |
263 | } |
264 | return; |
265 | } |
266 | |
267 | static const struct pci_device_id mantis_pci_table[] = { |
268 | MAKE_ENTRY(TECHNISAT, CABLESTAR_HD2, &vp2040_config, |
269 | RC_MAP_TECHNISAT_TS35), |
270 | MAKE_ENTRY(TECHNISAT, SKYSTAR_HD2_10, &vp1041_config, |
271 | NULL), |
272 | MAKE_ENTRY(TECHNISAT, SKYSTAR_HD2_20, &vp1041_config, |
273 | NULL), |
274 | MAKE_ENTRY(TERRATEC, CINERGY_C, &vp2040_config, |
275 | RC_MAP_TERRATEC_CINERGY_C_PCI), |
276 | MAKE_ENTRY(TERRATEC, CINERGY_S2_PCI_HD, &vp1041_config, |
277 | RC_MAP_TERRATEC_CINERGY_S2_HD), |
278 | MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1033_DVB_S, &vp1033_config, |
279 | NULL), |
280 | MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1034_DVB_S, &vp1034_config, |
281 | NULL), |
282 | MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1041_DVB_S2, &vp1041_config, |
283 | RC_MAP_TWINHAN_DTV_CAB_CI), |
284 | MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_2033_DVB_C, &vp2033_config, |
285 | RC_MAP_TWINHAN_DTV_CAB_CI), |
286 | MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_2040_DVB_C, &vp2040_config, |
287 | NULL), |
288 | MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3030_DVB_T, &vp3030_config, |
289 | NULL), |
290 | { } |
291 | }; |
292 | |
293 | MODULE_DEVICE_TABLE(pci, mantis_pci_table); |
294 | |
295 | static struct pci_driver mantis_pci_driver = { |
296 | .name = DRIVER_NAME, |
297 | .id_table = mantis_pci_table, |
298 | .probe = mantis_pci_probe, |
299 | .remove = mantis_pci_remove, |
300 | }; |
301 | |
302 | module_pci_driver(mantis_pci_driver); |
303 | |
304 | MODULE_DESCRIPTION("MANTIS driver" ); |
305 | MODULE_AUTHOR("Manu Abraham" ); |
306 | MODULE_LICENSE("GPL" ); |
307 | |