1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * This is the driver for the MGB4 video grabber card by Digiteq Automotive. |
4 | * |
5 | * Copyright (C) 2021-2023 Digiteq Automotive |
6 | * author: Martin Tuma <martin.tuma@digiteqautomotive.com> |
7 | * |
8 | * This is the main driver module. The DMA, I2C and SPI sub-drivers are |
9 | * initialized here and the input/output v4l2 devices are created. |
10 | * |
11 | * The mgb4 card uses different expansion modules for different video sources |
12 | * (GMSL and FPDL3 for now) so in probe() we detect the module type based on |
13 | * what we see on the I2C bus and check if it matches the FPGA bitstream (there |
14 | * are different bitstreams for different expansion modules). When no expansion |
15 | * module is present, we still let the driver initialize to allow flashing of |
16 | * the FPGA firmware using the SPI FLASH device. No v4l2 video devices are |
17 | * created in this case. |
18 | */ |
19 | |
20 | #include <linux/types.h> |
21 | #include <linux/module.h> |
22 | #include <linux/pci.h> |
23 | #include <linux/platform_device.h> |
24 | #include <linux/clk.h> |
25 | #include <linux/clk-provider.h> |
26 | #include <linux/clkdev.h> |
27 | #include <linux/i2c.h> |
28 | #include <linux/delay.h> |
29 | #include <linux/dma/amd_xdma.h> |
30 | #include <linux/platform_data/amd_xdma.h> |
31 | #include <linux/spi/xilinx_spi.h> |
32 | #include <linux/mtd/mtd.h> |
33 | #include <linux/hwmon.h> |
34 | #include <linux/debugfs.h> |
35 | #include "mgb4_dma.h" |
36 | #include "mgb4_i2c.h" |
37 | #include "mgb4_sysfs.h" |
38 | #include "mgb4_vout.h" |
39 | #include "mgb4_vin.h" |
40 | #include "mgb4_trigger.h" |
41 | #include "mgb4_core.h" |
42 | |
43 | #define MGB4_USER_IRQS 16 |
44 | |
45 | #define DIGITEQ_VID 0x1ed8 |
46 | #define T100_DID 0x0101 |
47 | #define T200_DID 0x0201 |
48 | |
49 | ATTRIBUTE_GROUPS(mgb4_pci); |
50 | |
51 | static int flashid; |
52 | |
53 | static struct xdma_chan_info h2c_chan_info = { |
54 | .dir = DMA_MEM_TO_DEV, |
55 | }; |
56 | |
57 | static struct xdma_chan_info c2h_chan_info = { |
58 | .dir = DMA_DEV_TO_MEM, |
59 | }; |
60 | |
61 | static struct xspi_platform_data spi_platform_data = { |
62 | .num_chipselect = 1, |
63 | .bits_per_word = 8 |
64 | }; |
65 | |
66 | static const struct i2c_board_info extender_info = { |
67 | I2C_BOARD_INFO("extender" , 0x21) |
68 | }; |
69 | |
70 | #if IS_REACHABLE(CONFIG_HWMON) |
71 | static umode_t temp_is_visible(const void *data, enum hwmon_sensor_types type, |
72 | u32 attr, int channel) |
73 | { |
74 | if (type == hwmon_temp && |
75 | (attr == hwmon_temp_input || attr == hwmon_temp_label)) |
76 | return 0444; |
77 | else |
78 | return 0; |
79 | } |
80 | |
81 | static int temp_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, |
82 | int channel, long *val) |
83 | { |
84 | struct mgb4_dev *mgbdev = dev_get_drvdata(dev); |
85 | u32 val10, raw; |
86 | |
87 | if (type != hwmon_temp || attr != hwmon_temp_input) |
88 | return -EOPNOTSUPP; |
89 | |
90 | raw = mgb4_read_reg(&mgbdev->video, 0xD0); |
91 | /* register value -> Celsius degrees formula given by Xilinx */ |
92 | val10 = ((((raw >> 20) & 0xFFF) * 503975) - 1118822400) / 409600; |
93 | *val = val10 * 100; |
94 | |
95 | return 0; |
96 | } |
97 | |
98 | static int temp_read_string(struct device *dev, enum hwmon_sensor_types type, |
99 | u32 attr, int channel, const char **str) |
100 | { |
101 | if (type != hwmon_temp || attr != hwmon_temp_label) |
102 | return -EOPNOTSUPP; |
103 | |
104 | *str = "FPGA Temperature" ; |
105 | |
106 | return 0; |
107 | } |
108 | |
109 | static const struct hwmon_ops temp_ops = { |
110 | .is_visible = temp_is_visible, |
111 | .read = temp_read, |
112 | .read_string = temp_read_string |
113 | }; |
114 | |
115 | static const struct hwmon_channel_info *temp_channel_info[] = { |
116 | HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_LABEL), |
117 | NULL |
118 | }; |
119 | |
120 | static const struct hwmon_chip_info temp_chip_info = { |
121 | .ops = &temp_ops, |
122 | .info = temp_channel_info, |
123 | }; |
124 | #endif |
125 | |
126 | static int match_i2c_adap(struct device *dev, void *data) |
127 | { |
128 | return i2c_verify_adapter(dev) ? 1 : 0; |
129 | } |
130 | |
131 | static struct i2c_adapter *get_i2c_adap(struct platform_device *pdev) |
132 | { |
133 | struct device *dev; |
134 | |
135 | mutex_lock(&pdev->dev.mutex); |
136 | dev = device_find_child(dev: &pdev->dev, NULL, match: match_i2c_adap); |
137 | mutex_unlock(lock: &pdev->dev.mutex); |
138 | |
139 | return dev ? to_i2c_adapter(dev) : NULL; |
140 | } |
141 | |
142 | static int match_spi_adap(struct device *dev, void *data) |
143 | { |
144 | return to_spi_device(dev) ? 1 : 0; |
145 | } |
146 | |
147 | static struct spi_controller *get_spi_adap(struct platform_device *pdev) |
148 | { |
149 | struct device *dev; |
150 | |
151 | mutex_lock(&pdev->dev.mutex); |
152 | dev = device_find_child(dev: &pdev->dev, NULL, match: match_spi_adap); |
153 | mutex_unlock(lock: &pdev->dev.mutex); |
154 | |
155 | return dev ? container_of(dev, struct spi_controller, dev) : NULL; |
156 | } |
157 | |
158 | static int init_spi(struct mgb4_dev *mgbdev, u32 devid) |
159 | { |
160 | struct resource spi_resources[] = { |
161 | { |
162 | .start = 0x400, |
163 | .end = 0x47f, |
164 | .flags = IORESOURCE_MEM, |
165 | .name = "io-memory" , |
166 | }, |
167 | { |
168 | .start = 14, |
169 | .end = 14, |
170 | .flags = IORESOURCE_IRQ, |
171 | .name = "irq" , |
172 | }, |
173 | }; |
174 | struct spi_board_info spi_info = { |
175 | .max_speed_hz = 10000000, |
176 | .modalias = "m25p80" , |
177 | .chip_select = 0, |
178 | .mode = SPI_MODE_3, |
179 | }; |
180 | struct pci_dev *pdev = mgbdev->pdev; |
181 | struct device *dev = &pdev->dev; |
182 | struct spi_controller *ctlr; |
183 | struct spi_device *spi_dev; |
184 | u32 irq; |
185 | int rv, id; |
186 | resource_size_t mapbase = pci_resource_start(pdev, MGB4_MGB4_BAR_ID); |
187 | |
188 | request_module("platform:xilinx_spi" ); |
189 | |
190 | irq = xdma_get_user_irq(pdev: mgbdev->xdev, user_irq_index: 14); |
191 | xdma_enable_user_irq(pdev: mgbdev->xdev, irq_num: irq); |
192 | |
193 | spi_resources[0].parent = &pdev->resource[MGB4_MGB4_BAR_ID]; |
194 | spi_resources[0].start += mapbase; |
195 | spi_resources[0].end += mapbase; |
196 | spi_resources[1].start = irq; |
197 | spi_resources[1].end = irq; |
198 | |
199 | id = pci_dev_id(dev: pdev); |
200 | mgbdev->spi_pdev = platform_device_register_resndata(parent: dev, name: "xilinx_spi" , |
201 | id, res: spi_resources, |
202 | ARRAY_SIZE(spi_resources), |
203 | data: &spi_platform_data, |
204 | size: sizeof(spi_platform_data)); |
205 | if (IS_ERR(ptr: mgbdev->spi_pdev)) { |
206 | dev_err(dev, "failed to register SPI device\n" ); |
207 | return PTR_ERR(ptr: mgbdev->spi_pdev); |
208 | } |
209 | |
210 | ctlr = get_spi_adap(pdev: mgbdev->spi_pdev); |
211 | if (!ctlr) { |
212 | dev_err(dev, "failed to get SPI adapter\n" ); |
213 | rv = -EINVAL; |
214 | goto err_pdev; |
215 | } |
216 | |
217 | snprintf(buf: mgbdev->fw_part_name, size: sizeof(mgbdev->fw_part_name), |
218 | fmt: "mgb4-fw.%d" , flashid); |
219 | mgbdev->partitions[0].name = mgbdev->fw_part_name; |
220 | if (devid == T200_DID) { |
221 | mgbdev->partitions[0].size = 0x950000; |
222 | mgbdev->partitions[0].offset = 0x1000000; |
223 | } else { |
224 | mgbdev->partitions[0].size = 0x400000; |
225 | mgbdev->partitions[0].offset = 0x400000; |
226 | } |
227 | mgbdev->partitions[0].mask_flags = 0; |
228 | |
229 | snprintf(buf: mgbdev->data_part_name, size: sizeof(mgbdev->data_part_name), |
230 | fmt: "mgb4-data.%d" , flashid); |
231 | mgbdev->partitions[1].name = mgbdev->data_part_name; |
232 | mgbdev->partitions[1].size = 0x10000; |
233 | mgbdev->partitions[1].offset = 0xFF0000; |
234 | mgbdev->partitions[1].mask_flags = MTD_CAP_NORFLASH; |
235 | |
236 | snprintf(buf: mgbdev->flash_name, size: sizeof(mgbdev->flash_name), |
237 | fmt: "mgb4-flash.%d" , flashid); |
238 | mgbdev->flash_data.name = mgbdev->flash_name; |
239 | mgbdev->flash_data.parts = mgbdev->partitions; |
240 | mgbdev->flash_data.nr_parts = ARRAY_SIZE(mgbdev->partitions); |
241 | mgbdev->flash_data.type = "spi-nor" ; |
242 | |
243 | spi_info.platform_data = &mgbdev->flash_data; |
244 | |
245 | spi_dev = spi_new_device(ctlr, &spi_info); |
246 | put_device(dev: &ctlr->dev); |
247 | if (!spi_dev) { |
248 | dev_err(dev, "failed to create MTD device\n" ); |
249 | rv = -EINVAL; |
250 | goto err_pdev; |
251 | } |
252 | |
253 | return 0; |
254 | |
255 | err_pdev: |
256 | platform_device_unregister(mgbdev->spi_pdev); |
257 | |
258 | return rv; |
259 | } |
260 | |
261 | static void free_spi(struct mgb4_dev *mgbdev) |
262 | { |
263 | platform_device_unregister(mgbdev->spi_pdev); |
264 | } |
265 | |
266 | static int init_i2c(struct mgb4_dev *mgbdev) |
267 | { |
268 | struct resource i2c_resources[] = { |
269 | { |
270 | .start = 0x200, |
271 | .end = 0x3ff, |
272 | .flags = IORESOURCE_MEM, |
273 | .name = "io-memory" , |
274 | }, |
275 | { |
276 | .start = 15, |
277 | .end = 15, |
278 | .flags = IORESOURCE_IRQ, |
279 | .name = "irq" , |
280 | }, |
281 | }; |
282 | struct pci_dev *pdev = mgbdev->pdev; |
283 | struct device *dev = &pdev->dev; |
284 | char clk_name[16]; |
285 | u32 irq; |
286 | int rv, id; |
287 | resource_size_t mapbase = pci_resource_start(pdev, MGB4_MGB4_BAR_ID); |
288 | |
289 | request_module("platform:xiic-i2c" ); |
290 | |
291 | irq = xdma_get_user_irq(pdev: mgbdev->xdev, user_irq_index: 15); |
292 | xdma_enable_user_irq(pdev: mgbdev->xdev, irq_num: irq); |
293 | |
294 | i2c_resources[0].parent = &pdev->resource[MGB4_MGB4_BAR_ID]; |
295 | i2c_resources[0].start += mapbase; |
296 | i2c_resources[0].end += mapbase; |
297 | i2c_resources[1].start = irq; |
298 | i2c_resources[1].end = irq; |
299 | |
300 | id = pci_dev_id(dev: pdev); |
301 | |
302 | /* create dummy clock required by the xiic-i2c adapter */ |
303 | snprintf(buf: clk_name, size: sizeof(clk_name), fmt: "xiic-i2c.%d" , id); |
304 | mgbdev->i2c_clk = clk_hw_register_fixed_rate(NULL, clk_name, NULL, |
305 | 0, 125000000); |
306 | if (IS_ERR(ptr: mgbdev->i2c_clk)) { |
307 | dev_err(dev, "failed to register I2C clock\n" ); |
308 | return PTR_ERR(ptr: mgbdev->i2c_clk); |
309 | } |
310 | mgbdev->i2c_cl = clkdev_hw_create(hw: mgbdev->i2c_clk, NULL, dev_fmt: "xiic-i2c.%d" , |
311 | id); |
312 | if (!mgbdev->i2c_cl) { |
313 | dev_err(dev, "failed to register I2C clockdev\n" ); |
314 | rv = -ENOMEM; |
315 | goto err_clk; |
316 | } |
317 | |
318 | mgbdev->i2c_pdev = platform_device_register_resndata(parent: dev, name: "xiic-i2c" , |
319 | id, res: i2c_resources, |
320 | ARRAY_SIZE(i2c_resources), |
321 | NULL, size: 0); |
322 | if (IS_ERR(ptr: mgbdev->i2c_pdev)) { |
323 | dev_err(dev, "failed to register I2C device\n" ); |
324 | rv = PTR_ERR(ptr: mgbdev->i2c_pdev); |
325 | goto err_clkdev; |
326 | } |
327 | |
328 | mgbdev->i2c_adap = get_i2c_adap(pdev: mgbdev->i2c_pdev); |
329 | if (!mgbdev->i2c_adap) { |
330 | dev_err(dev, "failed to get I2C adapter\n" ); |
331 | rv = -EINVAL; |
332 | goto err_pdev; |
333 | } |
334 | |
335 | mutex_init(&mgbdev->i2c_lock); |
336 | |
337 | return 0; |
338 | |
339 | err_pdev: |
340 | platform_device_unregister(mgbdev->i2c_pdev); |
341 | err_clkdev: |
342 | clkdev_drop(cl: mgbdev->i2c_cl); |
343 | err_clk: |
344 | clk_hw_unregister(hw: mgbdev->i2c_clk); |
345 | |
346 | return rv; |
347 | } |
348 | |
349 | static void free_i2c(struct mgb4_dev *mgbdev) |
350 | { |
351 | put_device(dev: &mgbdev->i2c_adap->dev); |
352 | platform_device_unregister(mgbdev->i2c_pdev); |
353 | clkdev_drop(cl: mgbdev->i2c_cl); |
354 | clk_hw_unregister(hw: mgbdev->i2c_clk); |
355 | } |
356 | |
357 | static int get_serial_number(struct mgb4_dev *mgbdev) |
358 | { |
359 | struct device *dev = &mgbdev->pdev->dev; |
360 | struct mtd_info *mtd; |
361 | size_t rs; |
362 | int rv; |
363 | |
364 | mgbdev->serial_number = 0; |
365 | |
366 | mtd = get_mtd_device_nm(name: mgbdev->data_part_name); |
367 | if (IS_ERR(ptr: mtd)) { |
368 | dev_warn(dev, "failed to get data MTD device\n" ); |
369 | return -ENOENT; |
370 | } |
371 | rv = mtd_read(mtd, from: 0, len: sizeof(mgbdev->serial_number), retlen: &rs, |
372 | buf: (u_char *)&mgbdev->serial_number); |
373 | put_mtd_device(mtd); |
374 | if (rv < 0 || rs != sizeof(mgbdev->serial_number)) { |
375 | dev_warn(dev, "error reading MTD device\n" ); |
376 | return -EIO; |
377 | } |
378 | |
379 | return 0; |
380 | } |
381 | |
382 | static int get_module_version(struct mgb4_dev *mgbdev) |
383 | { |
384 | struct device *dev = &mgbdev->pdev->dev; |
385 | struct mgb4_i2c_client extender; |
386 | s32 version; |
387 | u32 fw_version; |
388 | int rv; |
389 | |
390 | rv = mgb4_i2c_init(client: &extender, adap: mgbdev->i2c_adap, info: &extender_info, addr_size: 8); |
391 | if (rv < 0) { |
392 | dev_err(dev, "failed to create extender I2C device\n" ); |
393 | return rv; |
394 | } |
395 | version = mgb4_i2c_read_byte(client: &extender, reg: 0x00); |
396 | mgb4_i2c_free(client: &extender); |
397 | if (version < 0) { |
398 | dev_err(dev, "error reading module version\n" ); |
399 | return -EIO; |
400 | } |
401 | |
402 | mgbdev->module_version = ~((u32)version) & 0xff; |
403 | if (!(MGB4_IS_FPDL3(mgbdev) || MGB4_IS_GMSL(mgbdev))) { |
404 | dev_err(dev, "unknown module type\n" ); |
405 | return -EINVAL; |
406 | } |
407 | fw_version = mgb4_read_reg(&mgbdev->video, 0xC4); |
408 | if (fw_version >> 24 != mgbdev->module_version >> 4) { |
409 | dev_err(dev, "module/firmware type mismatch\n" ); |
410 | return -EINVAL; |
411 | } |
412 | |
413 | dev_info(dev, "%s module detected\n" , |
414 | MGB4_IS_FPDL3(mgbdev) ? "FPDL3" : "GMSL" ); |
415 | |
416 | return 0; |
417 | } |
418 | |
419 | static int map_regs(struct pci_dev *pdev, struct resource *res, |
420 | struct mgb4_regs *regs) |
421 | { |
422 | int rv; |
423 | resource_size_t mapbase = pci_resource_start(pdev, MGB4_MGB4_BAR_ID); |
424 | |
425 | res->start += mapbase; |
426 | res->end += mapbase; |
427 | |
428 | rv = mgb4_regs_map(res, regs); |
429 | if (rv < 0) { |
430 | dev_err(&pdev->dev, "failed to map %s registers\n" , res->name); |
431 | return rv; |
432 | } |
433 | |
434 | return 0; |
435 | } |
436 | |
437 | static int init_xdma(struct mgb4_dev *mgbdev) |
438 | { |
439 | struct xdma_platdata data; |
440 | struct resource res[2] = { 0 }; |
441 | struct dma_slave_map *map; |
442 | struct pci_dev *pdev = mgbdev->pdev; |
443 | struct device *dev = &pdev->dev; |
444 | int i; |
445 | |
446 | res[0].start = pci_resource_start(pdev, MGB4_XDMA_BAR_ID); |
447 | res[0].end = pci_resource_end(pdev, MGB4_XDMA_BAR_ID); |
448 | res[0].flags = IORESOURCE_MEM; |
449 | res[0].parent = &pdev->resource[MGB4_XDMA_BAR_ID]; |
450 | res[1].start = pci_irq_vector(dev: pdev, nr: 0); |
451 | res[1].end = res[1].start + MGB4_VIN_DEVICES + MGB4_VOUT_DEVICES |
452 | + MGB4_USER_IRQS - 1; |
453 | res[1].flags = IORESOURCE_IRQ; |
454 | |
455 | data.max_dma_channels = MGB4_VIN_DEVICES + MGB4_VOUT_DEVICES; |
456 | data.device_map = mgbdev->slave_map; |
457 | data.device_map_cnt = MGB4_VIN_DEVICES + MGB4_VOUT_DEVICES; |
458 | |
459 | for (i = 0; i < MGB4_VIN_DEVICES; i++) { |
460 | sprintf(buf: mgbdev->channel_names[i], fmt: "c2h%d" , i); |
461 | map = &data.device_map[i]; |
462 | map->slave = mgbdev->channel_names[i]; |
463 | map->devname = dev_name(dev); |
464 | map->param = XDMA_FILTER_PARAM(&c2h_chan_info); |
465 | } |
466 | for (i = 0; i < MGB4_VOUT_DEVICES; i++) { |
467 | sprintf(buf: mgbdev->channel_names[i + MGB4_VIN_DEVICES], fmt: "h2c%d" , i); |
468 | map = &data.device_map[i + MGB4_VIN_DEVICES]; |
469 | map->slave = mgbdev->channel_names[i + MGB4_VIN_DEVICES]; |
470 | map->devname = dev_name(dev); |
471 | map->param = XDMA_FILTER_PARAM(&h2c_chan_info); |
472 | } |
473 | |
474 | mgbdev->xdev = platform_device_register_resndata(parent: dev, name: "xdma" , |
475 | PLATFORM_DEVID_AUTO, res, |
476 | num: 2, data: &data, size: sizeof(data)); |
477 | if (IS_ERR(ptr: mgbdev->xdev)) { |
478 | dev_err(dev, "failed to register XDMA device\n" ); |
479 | return PTR_ERR(ptr: mgbdev->xdev); |
480 | } |
481 | |
482 | return 0; |
483 | } |
484 | |
485 | static void free_xdma(struct mgb4_dev *mgbdev) |
486 | { |
487 | platform_device_unregister(mgbdev->xdev); |
488 | } |
489 | |
490 | static int mgb4_probe(struct pci_dev *pdev, const struct pci_device_id *id) |
491 | { |
492 | int i, rv; |
493 | struct mgb4_dev *mgbdev; |
494 | struct resource video = { |
495 | .start = 0x0, |
496 | .end = 0x100, |
497 | .flags = IORESOURCE_MEM, |
498 | .name = "mgb4-video" , |
499 | }; |
500 | struct resource cmt = { |
501 | .start = 0x1000, |
502 | .end = 0x1800, |
503 | .flags = IORESOURCE_MEM, |
504 | .name = "mgb4-cmt" , |
505 | }; |
506 | int irqs = pci_msix_vec_count(dev: pdev); |
507 | |
508 | mgbdev = kzalloc(size: sizeof(*mgbdev), GFP_KERNEL); |
509 | if (!mgbdev) |
510 | return -ENOMEM; |
511 | |
512 | mgbdev->pdev = pdev; |
513 | pci_set_drvdata(pdev, data: mgbdev); |
514 | |
515 | /* PCIe related stuff */ |
516 | rv = pci_enable_device(dev: pdev); |
517 | if (rv) { |
518 | dev_err(&pdev->dev, "error enabling PCI device\n" ); |
519 | goto err_mgbdev; |
520 | } |
521 | |
522 | rv = pcie_capability_set_word(dev: pdev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_RELAX_EN); |
523 | if (rv) |
524 | dev_warn(&pdev->dev, "error enabling PCIe relaxed ordering\n" ); |
525 | rv = pcie_capability_set_word(dev: pdev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_EXT_TAG); |
526 | if (rv) |
527 | dev_warn(&pdev->dev, "error enabling PCIe extended tag field\n" ); |
528 | rv = pcie_set_readrq(dev: pdev, rq: 512); |
529 | if (rv) |
530 | dev_warn(&pdev->dev, "error setting PCIe max. memory read size\n" ); |
531 | pci_set_master(dev: pdev); |
532 | |
533 | rv = pci_alloc_irq_vectors(dev: pdev, min_vecs: irqs, max_vecs: irqs, PCI_IRQ_MSIX); |
534 | if (rv < 0) { |
535 | dev_err(&pdev->dev, "error allocating MSI-X IRQs\n" ); |
536 | goto err_enable_pci; |
537 | } |
538 | |
539 | rv = dma_set_mask_and_coherent(dev: &pdev->dev, DMA_BIT_MASK(64)); |
540 | if (rv) { |
541 | dev_err(&pdev->dev, "error setting DMA mask\n" ); |
542 | goto err_enable_pci; |
543 | } |
544 | |
545 | /* DMA + IRQ engine */ |
546 | rv = init_xdma(mgbdev); |
547 | if (rv) |
548 | goto err_alloc_irq; |
549 | rv = mgb4_dma_channel_init(mgbdev); |
550 | if (rv) |
551 | goto err_dma_chan; |
552 | |
553 | /* mgb4 video registers */ |
554 | rv = map_regs(pdev, res: &video, regs: &mgbdev->video); |
555 | if (rv < 0) |
556 | goto err_dma_chan; |
557 | /* mgb4 cmt registers */ |
558 | rv = map_regs(pdev, res: &cmt, regs: &mgbdev->cmt); |
559 | if (rv < 0) |
560 | goto err_video_regs; |
561 | |
562 | /* SPI FLASH */ |
563 | rv = init_spi(mgbdev, devid: id->device); |
564 | if (rv < 0) |
565 | goto err_cmt_regs; |
566 | |
567 | /* I2C controller */ |
568 | rv = init_i2c(mgbdev); |
569 | if (rv < 0) |
570 | goto err_spi; |
571 | |
572 | /* PCI card related sysfs attributes */ |
573 | rv = device_add_groups(dev: &pdev->dev, groups: mgb4_pci_groups); |
574 | if (rv < 0) |
575 | goto err_i2c; |
576 | |
577 | #if IS_REACHABLE(CONFIG_HWMON) |
578 | /* HWmon (card temperature) */ |
579 | mgbdev->hwmon_dev = hwmon_device_register_with_info(dev: &pdev->dev, name: "mgb4" , |
580 | drvdata: mgbdev, |
581 | info: &temp_chip_info, |
582 | NULL); |
583 | #endif |
584 | |
585 | #ifdef CONFIG_DEBUG_FS |
586 | mgbdev->debugfs = debugfs_create_dir(name: dev_name(dev: &pdev->dev), NULL); |
587 | #endif |
588 | |
589 | /* Get card serial number. On systems without MTD flash support we may |
590 | * get an error thus ignore the return value. An invalid serial number |
591 | * should not break anything... |
592 | */ |
593 | if (get_serial_number(mgbdev) < 0) |
594 | dev_warn(&pdev->dev, "error reading card serial number\n" ); |
595 | |
596 | /* Get module type. If no valid module is found, skip the video device |
597 | * creation part but do not exit with error to allow flashing the card. |
598 | */ |
599 | rv = get_module_version(mgbdev); |
600 | if (rv < 0) |
601 | goto exit; |
602 | |
603 | /* Video input v4l2 devices */ |
604 | for (i = 0; i < MGB4_VIN_DEVICES; i++) |
605 | mgbdev->vin[i] = mgb4_vin_create(mgbdev, id: i); |
606 | |
607 | /* Video output v4l2 devices */ |
608 | for (i = 0; i < MGB4_VOUT_DEVICES; i++) |
609 | mgbdev->vout[i] = mgb4_vout_create(mgbdev, id: i); |
610 | |
611 | /* Triggers */ |
612 | mgbdev->indio_dev = mgb4_trigger_create(mgbdev); |
613 | |
614 | exit: |
615 | flashid++; |
616 | |
617 | return 0; |
618 | |
619 | err_i2c: |
620 | free_i2c(mgbdev); |
621 | err_spi: |
622 | free_spi(mgbdev); |
623 | err_cmt_regs: |
624 | mgb4_regs_free(regs: &mgbdev->cmt); |
625 | err_video_regs: |
626 | mgb4_regs_free(regs: &mgbdev->video); |
627 | err_dma_chan: |
628 | mgb4_dma_channel_free(mgbdev); |
629 | free_xdma(mgbdev); |
630 | err_alloc_irq: |
631 | pci_disable_msix(dev: pdev); |
632 | err_enable_pci: |
633 | pci_disable_device(dev: pdev); |
634 | err_mgbdev: |
635 | kfree(objp: mgbdev); |
636 | |
637 | return rv; |
638 | } |
639 | |
640 | static void mgb4_remove(struct pci_dev *pdev) |
641 | { |
642 | struct mgb4_dev *mgbdev = pci_get_drvdata(pdev); |
643 | int i; |
644 | |
645 | #ifdef CONFIG_DEBUG_FS |
646 | debugfs_remove_recursive(dentry: mgbdev->debugfs); |
647 | #endif |
648 | #if IS_REACHABLE(CONFIG_HWMON) |
649 | hwmon_device_unregister(dev: mgbdev->hwmon_dev); |
650 | #endif |
651 | |
652 | if (mgbdev->indio_dev) |
653 | mgb4_trigger_free(indio_dev: mgbdev->indio_dev); |
654 | |
655 | for (i = 0; i < MGB4_VOUT_DEVICES; i++) |
656 | if (mgbdev->vout[i]) |
657 | mgb4_vout_free(voutdev: mgbdev->vout[i]); |
658 | for (i = 0; i < MGB4_VIN_DEVICES; i++) |
659 | if (mgbdev->vin[i]) |
660 | mgb4_vin_free(vindev: mgbdev->vin[i]); |
661 | |
662 | device_remove_groups(dev: &mgbdev->pdev->dev, groups: mgb4_pci_groups); |
663 | free_spi(mgbdev); |
664 | free_i2c(mgbdev); |
665 | mgb4_regs_free(regs: &mgbdev->video); |
666 | mgb4_regs_free(regs: &mgbdev->cmt); |
667 | |
668 | mgb4_dma_channel_free(mgbdev); |
669 | free_xdma(mgbdev); |
670 | |
671 | pci_disable_msix(dev: mgbdev->pdev); |
672 | pci_disable_device(dev: mgbdev->pdev); |
673 | |
674 | kfree(objp: mgbdev); |
675 | } |
676 | |
677 | static const struct pci_device_id mgb4_pci_ids[] = { |
678 | { PCI_DEVICE(DIGITEQ_VID, T100_DID), }, |
679 | { PCI_DEVICE(DIGITEQ_VID, T200_DID), }, |
680 | { 0, } |
681 | }; |
682 | MODULE_DEVICE_TABLE(pci, mgb4_pci_ids); |
683 | |
684 | static struct pci_driver mgb4_pci_driver = { |
685 | .name = KBUILD_MODNAME, |
686 | .id_table = mgb4_pci_ids, |
687 | .probe = mgb4_probe, |
688 | .remove = mgb4_remove, |
689 | }; |
690 | |
691 | module_pci_driver(mgb4_pci_driver); |
692 | |
693 | MODULE_AUTHOR("Digiteq Automotive s.r.o." ); |
694 | MODULE_DESCRIPTION("Digiteq Automotive MGB4 Driver" ); |
695 | MODULE_LICENSE("GPL" ); |
696 | MODULE_SOFTDEP("pre: platform:xiic-i2c platform:xilinx_spi spi-nor" ); |
697 | |