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#include <linux/clk.h>
30#include <linux/clkdev.h>
31#include <linux/clk-provider.h>
32#include <linux/delay.h>
33#include <linux/interrupt.h>
34#include <linux/math64.h>
35#include <linux/module.h>
36#include <linux/of.h>
37#include <linux/of_graph.h>
38#include <linux/platform_device.h>
39#include <linux/pm_runtime.h>
40#include <linux/regmap.h>
41#include <linux/videodev2.h>
42
43#include <media/v4l2-ctrls.h>
44#include <media/v4l2-device.h>
45#include <media/v4l2-event.h>
46#include <media/v4l2-image-sizes.h>
47#include <media/v4l2-ioctl.h>
48#include <media/v4l2-fwnode.h>
49#include <media/v4l2-subdev.h>
50#include <media/videobuf2-dma-contig.h>
51
52#include "atmel-isc-regs.h"
53#include "atmel-isc.h"
54
55#define ISC_SAMA7G5_MAX_SUPPORT_WIDTH 3264
56#define ISC_SAMA7G5_MAX_SUPPORT_HEIGHT 2464
57
58#define ISC_SAMA7G5_PIPELINE \
59 (WB_ENABLE | CFA_ENABLE | CC_ENABLE | GAM_ENABLES | CSC_ENABLE | \
60 CBC_ENABLE | SUB422_ENABLE | SUB420_ENABLE)
61
62
63static const struct isc_format sama7g5_controller_formats[] = {
64 {
65 .fourcc = V4L2_PIX_FMT_ARGB444,
66 },
67 {
68 .fourcc = V4L2_PIX_FMT_ARGB555,
69 },
70 {
71 .fourcc = V4L2_PIX_FMT_RGB565,
72 },
73 {
74 .fourcc = V4L2_PIX_FMT_ABGR32,
75 },
76 {
77 .fourcc = V4L2_PIX_FMT_XBGR32,
78 },
79 {
80 .fourcc = V4L2_PIX_FMT_YUV420,
81 },
82 {
83 .fourcc = V4L2_PIX_FMT_UYVY,
84 },
85 {
86 .fourcc = V4L2_PIX_FMT_VYUY,
87 },
88 {
89 .fourcc = V4L2_PIX_FMT_YUYV,
90 },
91 {
92 .fourcc = V4L2_PIX_FMT_YUV422P,
93 },
94 {
95 .fourcc = V4L2_PIX_FMT_GREY,
96 },
97 {
98 .fourcc = V4L2_PIX_FMT_Y10,
99 },
100 {
101 .fourcc = V4L2_PIX_FMT_Y16,
102 },
103};
104
105
106static struct isc_format sama7g5_formats_list[] = {
107 {
108 .fourcc = V4L2_PIX_FMT_SBGGR8,
109 .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,
110 .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
111 .cfa_baycfg = ISC_BAY_CFG_BGBG,
112 },
113 {
114 .fourcc = V4L2_PIX_FMT_SGBRG8,
115 .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8,
116 .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
117 .cfa_baycfg = ISC_BAY_CFG_GBGB,
118 },
119 {
120 .fourcc = V4L2_PIX_FMT_SGRBG8,
121 .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8,
122 .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
123 .cfa_baycfg = ISC_BAY_CFG_GRGR,
124 },
125 {
126 .fourcc = V4L2_PIX_FMT_SRGGB8,
127 .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8,
128 .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
129 .cfa_baycfg = ISC_BAY_CFG_RGRG,
130 },
131 {
132 .fourcc = V4L2_PIX_FMT_SBGGR10,
133 .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10,
134 .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
135 .cfa_baycfg = ISC_BAY_CFG_RGRG,
136 },
137 {
138 .fourcc = V4L2_PIX_FMT_SGBRG10,
139 .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10,
140 .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
141 .cfa_baycfg = ISC_BAY_CFG_GBGB,
142 },
143 {
144 .fourcc = V4L2_PIX_FMT_SGRBG10,
145 .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10,
146 .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
147 .cfa_baycfg = ISC_BAY_CFG_GRGR,
148 },
149 {
150 .fourcc = V4L2_PIX_FMT_SRGGB10,
151 .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10,
152 .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
153 .cfa_baycfg = ISC_BAY_CFG_RGRG,
154 },
155 {
156 .fourcc = V4L2_PIX_FMT_SBGGR12,
157 .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12,
158 .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE,
159 .cfa_baycfg = ISC_BAY_CFG_BGBG,
160 },
161 {
162 .fourcc = V4L2_PIX_FMT_SGBRG12,
163 .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12,
164 .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE,
165 .cfa_baycfg = ISC_BAY_CFG_GBGB,
166 },
167 {
168 .fourcc = V4L2_PIX_FMT_SGRBG12,
169 .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12,
170 .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE,
171 .cfa_baycfg = ISC_BAY_CFG_GRGR,
172 },
173 {
174 .fourcc = V4L2_PIX_FMT_SRGGB12,
175 .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12,
176 .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE,
177 .cfa_baycfg = ISC_BAY_CFG_RGRG,
178 },
179 {
180 .fourcc = V4L2_PIX_FMT_GREY,
181 .mbus_code = MEDIA_BUS_FMT_Y8_1X8,
182 .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
183 },
184 {
185 .fourcc = V4L2_PIX_FMT_YUYV,
186 .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
187 .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
188 },
189 {
190 .fourcc = V4L2_PIX_FMT_UYVY,
191 .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
192 .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
193 },
194 {
195 .fourcc = V4L2_PIX_FMT_RGB565,
196 .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE,
197 .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
198 },
199 {
200 .fourcc = V4L2_PIX_FMT_Y10,
201 .mbus_code = MEDIA_BUS_FMT_Y10_1X10,
202 .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
203 },
204
205};
206
207static void isc_sama7g5_config_csc(struct isc_device *isc)
208{
209 struct regmap *regmap = isc->regmap;
210
211
212 regmap_write(regmap, ISC_CSC_YR_YG + isc->offsets.csc,
213 0x42 | (0x81 << 16));
214 regmap_write(regmap, ISC_CSC_YB_OY + isc->offsets.csc,
215 0x19 | (0x10 << 16));
216 regmap_write(regmap, ISC_CSC_CBR_CBG + isc->offsets.csc,
217 0xFDA | (0xFB6 << 16));
218 regmap_write(regmap, ISC_CSC_CBB_OCB + isc->offsets.csc,
219 0x70 | (0x80 << 16));
220 regmap_write(regmap, ISC_CSC_CRR_CRG + isc->offsets.csc,
221 0x70 | (0xFA2 << 16));
222 regmap_write(regmap, ISC_CSC_CRB_OCR + isc->offsets.csc,
223 0xFEE | (0x80 << 16));
224}
225
226static void isc_sama7g5_config_cbc(struct isc_device *isc)
227{
228 struct regmap *regmap = isc->regmap;
229
230
231 regmap_write(regmap, ISC_CBC_BRIGHT + isc->offsets.cbc, isc->ctrls.brightness);
232 regmap_write(regmap, ISC_CBC_CONTRAST + isc->offsets.cbc, isc->ctrls.contrast);
233
234 regmap_write(regmap, ISC_CBCHS_HUE, 0);
235 regmap_write(regmap, ISC_CBCHS_SAT, (1 << 4));
236}
237
238static void isc_sama7g5_config_cc(struct isc_device *isc)
239{
240 struct regmap *regmap = isc->regmap;
241
242
243 regmap_write(regmap, ISC_CC_RR_RG, (1 << 8));
244 regmap_write(regmap, ISC_CC_RB_OR, 0);
245 regmap_write(regmap, ISC_CC_GR_GG, (1 << 8) << 16);
246 regmap_write(regmap, ISC_CC_GB_OG, 0);
247 regmap_write(regmap, ISC_CC_BR_BG, 0);
248 regmap_write(regmap, ISC_CC_BB_OB, (1 << 8));
249}
250
251static void isc_sama7g5_config_ctrls(struct isc_device *isc,
252 const struct v4l2_ctrl_ops *ops)
253{
254 struct isc_ctrls *ctrls = &isc->ctrls;
255 struct v4l2_ctrl_handler *hdl = &ctrls->handler;
256
257 ctrls->contrast = 16;
258
259 v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -2048, 2047, 1, 16);
260}
261
262static void isc_sama7g5_config_dpc(struct isc_device *isc)
263{
264 u32 bay_cfg = isc->config.sd_format->cfa_baycfg;
265 struct regmap *regmap = isc->regmap;
266
267 regmap_update_bits(regmap, ISC_DPC_CFG, ISC_DPC_CFG_BLOFF_MASK,
268 (64 << ISC_DPC_CFG_BLOFF_SHIFT));
269 regmap_update_bits(regmap, ISC_DPC_CFG, ISC_DPC_CFG_BAYCFG_MASK,
270 (bay_cfg << ISC_DPC_CFG_BAYCFG_SHIFT));
271}
272
273static void isc_sama7g5_config_gam(struct isc_device *isc)
274{
275 struct regmap *regmap = isc->regmap;
276
277 regmap_update_bits(regmap, ISC_GAM_CTRL, ISC_GAM_CTRL_BIPART,
278 ISC_GAM_CTRL_BIPART);
279}
280
281static void isc_sama7g5_config_rlp(struct isc_device *isc)
282{
283 struct regmap *regmap = isc->regmap;
284 u32 rlp_mode = isc->config.rlp_cfg_mode;
285
286 regmap_update_bits(regmap, ISC_RLP_CFG + isc->offsets.rlp,
287 ISC_RLP_CFG_MODE_MASK | ISC_RLP_CFG_LSH |
288 ISC_RLP_CFG_YMODE_MASK, rlp_mode);
289}
290
291static void isc_sama7g5_adapt_pipeline(struct isc_device *isc)
292{
293 isc->try_config.bits_pipeline &= ISC_SAMA7G5_PIPELINE;
294}
295
296
297static const u32 isc_sama7g5_gamma_table[][GAMMA_ENTRIES] = {
298
299 {
300 0x980, 0x4c0320, 0x650260, 0x7801e0, 0x8701a0, 0x940180,
301 0xa00160, 0xab0120, 0xb40120, 0xbd0120, 0xc60100, 0xce0100,
302 0xd600e0, 0xdd00e0, 0xe400e0, 0xeb00c0, 0xf100c0, 0xf700c0,
303 0xfd00c0, 0x10300a0, 0x10800c0, 0x10e00a0, 0x11300a0, 0x11800a0,
304 0x11d00a0, 0x12200a0, 0x12700a0, 0x12c0080, 0x13000a0, 0x1350080,
305 0x13900a0, 0x13e0080, 0x1420076, 0x17d0062, 0x1ae0054, 0x1d8004a,
306 0x1fd0044, 0x21f003e, 0x23e003a, 0x25b0036, 0x2760032, 0x28f0030,
307 0x2a7002e, 0x2be002c, 0x2d4002c, 0x2ea0028, 0x2fe0028, 0x3120026,
308 0x3250024, 0x3370024, 0x3490022, 0x35a0022, 0x36b0020, 0x37b0020,
309 0x38b0020, 0x39b001e, 0x3aa001e, 0x3b9001c, 0x3c7001c, 0x3d5001c,
310 0x3e3001c, 0x3f1001c, 0x3ff001a, 0x40c001a },
311};
312
313static int xisc_parse_dt(struct device *dev, struct isc_device *isc)
314{
315 struct device_node *np = dev->of_node;
316 struct device_node *epn = NULL;
317 struct isc_subdev_entity *subdev_entity;
318 unsigned int flags;
319 int ret;
320 bool mipi_mode;
321
322 INIT_LIST_HEAD(&isc->subdev_entities);
323
324 mipi_mode = of_property_read_bool(np, "microchip,mipi-mode");
325
326 while (1) {
327 struct v4l2_fwnode_endpoint v4l2_epn = { .bus_type = 0 };
328
329 epn = of_graph_get_next_endpoint(np, epn);
330 if (!epn)
331 return 0;
332
333 ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(epn),
334 &v4l2_epn);
335 if (ret) {
336 ret = -EINVAL;
337 dev_err(dev, "Could not parse the endpoint\n");
338 break;
339 }
340
341 subdev_entity = devm_kzalloc(dev, sizeof(*subdev_entity),
342 GFP_KERNEL);
343 if (!subdev_entity) {
344 ret = -ENOMEM;
345 break;
346 }
347 subdev_entity->epn = epn;
348
349 flags = v4l2_epn.bus.parallel.flags;
350
351 if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
352 subdev_entity->pfe_cfg0 = ISC_PFE_CFG0_HPOL_LOW;
353
354 if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
355 subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_VPOL_LOW;
356
357 if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
358 subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_PPOL_LOW;
359
360 if (v4l2_epn.bus_type == V4L2_MBUS_BT656)
361 subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_CCIR_CRC |
362 ISC_PFE_CFG0_CCIR656;
363
364 if (mipi_mode)
365 subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_MIPI;
366
367 list_add_tail(&subdev_entity->list, &isc->subdev_entities);
368 }
369 of_node_put(epn);
370
371 return ret;
372}
373
374static int microchip_xisc_probe(struct platform_device *pdev)
375{
376 struct device *dev = &pdev->dev;
377 struct isc_device *isc;
378 struct resource *res;
379 void __iomem *io_base;
380 struct isc_subdev_entity *subdev_entity;
381 int irq;
382 int ret;
383 u32 ver;
384
385 isc = devm_kzalloc(dev, sizeof(*isc), GFP_KERNEL);
386 if (!isc)
387 return -ENOMEM;
388
389 platform_set_drvdata(pdev, isc);
390 isc->dev = dev;
391
392 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
393 io_base = devm_ioremap_resource(dev, res);
394 if (IS_ERR(io_base))
395 return PTR_ERR(io_base);
396
397 isc->regmap = devm_regmap_init_mmio(dev, io_base, &isc_regmap_config);
398 if (IS_ERR(isc->regmap)) {
399 ret = PTR_ERR(isc->regmap);
400 dev_err(dev, "failed to init register map: %d\n", ret);
401 return ret;
402 }
403
404 irq = platform_get_irq(pdev, 0);
405 if (irq < 0)
406 return irq;
407
408 ret = devm_request_irq(dev, irq, isc_interrupt, 0,
409 "microchip-sama7g5-xisc", isc);
410 if (ret < 0) {
411 dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
412 irq, ret);
413 return ret;
414 }
415
416 isc->gamma_table = isc_sama7g5_gamma_table;
417 isc->gamma_max = 0;
418
419 isc->max_width = ISC_SAMA7G5_MAX_SUPPORT_WIDTH;
420 isc->max_height = ISC_SAMA7G5_MAX_SUPPORT_HEIGHT;
421
422 isc->config_dpc = isc_sama7g5_config_dpc;
423 isc->config_csc = isc_sama7g5_config_csc;
424 isc->config_cbc = isc_sama7g5_config_cbc;
425 isc->config_cc = isc_sama7g5_config_cc;
426 isc->config_gam = isc_sama7g5_config_gam;
427 isc->config_rlp = isc_sama7g5_config_rlp;
428 isc->config_ctrls = isc_sama7g5_config_ctrls;
429
430 isc->adapt_pipeline = isc_sama7g5_adapt_pipeline;
431
432 isc->offsets.csc = ISC_SAMA7G5_CSC_OFFSET;
433 isc->offsets.cbc = ISC_SAMA7G5_CBC_OFFSET;
434 isc->offsets.sub422 = ISC_SAMA7G5_SUB422_OFFSET;
435 isc->offsets.sub420 = ISC_SAMA7G5_SUB420_OFFSET;
436 isc->offsets.rlp = ISC_SAMA7G5_RLP_OFFSET;
437 isc->offsets.his = ISC_SAMA7G5_HIS_OFFSET;
438 isc->offsets.dma = ISC_SAMA7G5_DMA_OFFSET;
439 isc->offsets.version = ISC_SAMA7G5_VERSION_OFFSET;
440 isc->offsets.his_entry = ISC_SAMA7G5_HIS_ENTRY_OFFSET;
441
442 isc->controller_formats = sama7g5_controller_formats;
443 isc->controller_formats_size = ARRAY_SIZE(sama7g5_controller_formats);
444 isc->formats_list = sama7g5_formats_list;
445 isc->formats_list_size = ARRAY_SIZE(sama7g5_formats_list);
446
447
448 isc->dcfg = ISC_DCFG_YMBSIZE_BEATS32 | ISC_DCFG_CMBSIZE_BEATS32;
449
450 ret = isc_pipeline_init(isc);
451 if (ret)
452 return ret;
453
454 isc->hclock = devm_clk_get(dev, "hclock");
455 if (IS_ERR(isc->hclock)) {
456 ret = PTR_ERR(isc->hclock);
457 dev_err(dev, "failed to get hclock: %d\n", ret);
458 return ret;
459 }
460
461 ret = clk_prepare_enable(isc->hclock);
462 if (ret) {
463 dev_err(dev, "failed to enable hclock: %d\n", ret);
464 return ret;
465 }
466
467 ret = isc_clk_init(isc);
468 if (ret) {
469 dev_err(dev, "failed to init isc clock: %d\n", ret);
470 goto unprepare_hclk;
471 }
472
473 isc->ispck = isc->isc_clks[ISC_ISPCK].clk;
474
475 ret = clk_prepare_enable(isc->ispck);
476 if (ret) {
477 dev_err(dev, "failed to enable ispck: %d\n", ret);
478 goto unprepare_hclk;
479 }
480
481
482 ret = clk_set_rate(isc->ispck, clk_get_rate(isc->hclock));
483 if (ret) {
484 dev_err(dev, "failed to set ispck rate: %d\n", ret);
485 goto unprepare_clk;
486 }
487
488 ret = v4l2_device_register(dev, &isc->v4l2_dev);
489 if (ret) {
490 dev_err(dev, "unable to register v4l2 device.\n");
491 goto unprepare_clk;
492 }
493
494 ret = xisc_parse_dt(dev, isc);
495 if (ret) {
496 dev_err(dev, "fail to parse device tree\n");
497 goto unregister_v4l2_device;
498 }
499
500 if (list_empty(&isc->subdev_entities)) {
501 dev_err(dev, "no subdev found\n");
502 ret = -ENODEV;
503 goto unregister_v4l2_device;
504 }
505
506 list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
507 struct v4l2_async_subdev *asd;
508
509 v4l2_async_notifier_init(&subdev_entity->notifier);
510
511 asd = v4l2_async_notifier_add_fwnode_remote_subdev(
512 &subdev_entity->notifier,
513 of_fwnode_handle(subdev_entity->epn),
514 struct v4l2_async_subdev);
515
516 of_node_put(subdev_entity->epn);
517 subdev_entity->epn = NULL;
518
519 if (IS_ERR(asd)) {
520 ret = PTR_ERR(asd);
521 goto cleanup_subdev;
522 }
523
524 subdev_entity->notifier.ops = &isc_async_ops;
525
526 ret = v4l2_async_notifier_register(&isc->v4l2_dev,
527 &subdev_entity->notifier);
528 if (ret) {
529 dev_err(dev, "fail to register async notifier\n");
530 goto cleanup_subdev;
531 }
532
533 if (video_is_registered(&isc->video_dev))
534 break;
535 }
536
537 pm_runtime_set_active(dev);
538 pm_runtime_enable(dev);
539 pm_request_idle(dev);
540
541 regmap_read(isc->regmap, ISC_VERSION + isc->offsets.version, &ver);
542 dev_info(dev, "Microchip XISC version %x\n", ver);
543
544 return 0;
545
546cleanup_subdev:
547 isc_subdev_cleanup(isc);
548
549unregister_v4l2_device:
550 v4l2_device_unregister(&isc->v4l2_dev);
551
552unprepare_clk:
553 clk_disable_unprepare(isc->ispck);
554unprepare_hclk:
555 clk_disable_unprepare(isc->hclock);
556
557 isc_clk_cleanup(isc);
558
559 return ret;
560}
561
562static int microchip_xisc_remove(struct platform_device *pdev)
563{
564 struct isc_device *isc = platform_get_drvdata(pdev);
565
566 pm_runtime_disable(&pdev->dev);
567
568 isc_subdev_cleanup(isc);
569
570 v4l2_device_unregister(&isc->v4l2_dev);
571
572 clk_disable_unprepare(isc->ispck);
573 clk_disable_unprepare(isc->hclock);
574
575 isc_clk_cleanup(isc);
576
577 return 0;
578}
579
580static int __maybe_unused xisc_runtime_suspend(struct device *dev)
581{
582 struct isc_device *isc = dev_get_drvdata(dev);
583
584 clk_disable_unprepare(isc->ispck);
585 clk_disable_unprepare(isc->hclock);
586
587 return 0;
588}
589
590static int __maybe_unused xisc_runtime_resume(struct device *dev)
591{
592 struct isc_device *isc = dev_get_drvdata(dev);
593 int ret;
594
595 ret = clk_prepare_enable(isc->hclock);
596 if (ret)
597 return ret;
598
599 ret = clk_prepare_enable(isc->ispck);
600 if (ret)
601 clk_disable_unprepare(isc->hclock);
602
603 return ret;
604}
605
606static const struct dev_pm_ops microchip_xisc_dev_pm_ops = {
607 SET_RUNTIME_PM_OPS(xisc_runtime_suspend, xisc_runtime_resume, NULL)
608};
609
610static const struct of_device_id microchip_xisc_of_match[] = {
611 { .compatible = "microchip,sama7g5-isc" },
612 { }
613};
614MODULE_DEVICE_TABLE(of, microchip_xisc_of_match);
615
616static struct platform_driver microchip_xisc_driver = {
617 .probe = microchip_xisc_probe,
618 .remove = microchip_xisc_remove,
619 .driver = {
620 .name = "microchip-sama7g5-xisc",
621 .pm = µchip_xisc_dev_pm_ops,
622 .of_match_table = of_match_ptr(microchip_xisc_of_match),
623 },
624};
625
626module_platform_driver(microchip_xisc_driver);
627
628MODULE_AUTHOR("Eugen Hristev <eugen.hristev@microchip.com>");
629MODULE_DESCRIPTION("The V4L2 driver for Microchip-XISC");
630MODULE_LICENSE("GPL v2");
631