GNU Linux-libre 6.8.7-gnu
[releases.git] / drivers / media / platform / microchip / microchip-sama7g5-isc.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Microchip eXtended Image Sensor Controller (XISC) driver
4  *
5  * Copyright (C) 2019-2021 Microchip Technology, Inc. and its subsidiaries
6  *
7  * Author: Eugen Hristev <eugen.hristev@microchip.com>
8  *
9  * Sensor-->PFE-->DPC-->WB-->CFA-->CC-->GAM-->VHXS-->CSC-->CBHS-->SUB-->RLP-->DMA-->HIS
10  *
11  * ISC video pipeline integrates the following submodules:
12  * PFE: Parallel Front End to sample the camera sensor input stream
13  * DPC: Defective Pixel Correction with black offset correction, green disparity
14  *      correction and defective pixel correction (3 modules total)
15  *  WB: Programmable white balance in the Bayer domain
16  * CFA: Color filter array interpolation module
17  *  CC: Programmable color correction
18  * GAM: Gamma correction
19  *VHXS: Vertical and Horizontal Scaler
20  * CSC: Programmable color space conversion
21  *CBHS: Contrast Brightness Hue and Saturation control
22  * SUB: This module performs YCbCr444 to YCbCr420 chrominance subsampling
23  * RLP: This module performs rounding, range limiting
24  *      and packing of the incoming data
25  * DMA: This module performs DMA master accesses to write frames to external RAM
26  * HIS: Histogram module performs statistic counters on the frames
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 "microchip-isc-regs.h"
53 #include "microchip-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 /* This is a list of the formats that the ISC can *output* */
63 static const struct isc_format sama7g5_controller_formats[] = {
64         {
65                 .fourcc         = V4L2_PIX_FMT_ARGB444,
66         }, {
67                 .fourcc         = V4L2_PIX_FMT_ARGB555,
68         }, {
69                 .fourcc         = V4L2_PIX_FMT_RGB565,
70         }, {
71                 .fourcc         = V4L2_PIX_FMT_ABGR32,
72         }, {
73                 .fourcc         = V4L2_PIX_FMT_XBGR32,
74         }, {
75                 .fourcc         = V4L2_PIX_FMT_YUV420,
76         }, {
77                 .fourcc         = V4L2_PIX_FMT_UYVY,
78         }, {
79                 .fourcc         = V4L2_PIX_FMT_VYUY,
80         }, {
81                 .fourcc         = V4L2_PIX_FMT_YUYV,
82         }, {
83                 .fourcc         = V4L2_PIX_FMT_YUV422P,
84         }, {
85                 .fourcc         = V4L2_PIX_FMT_GREY,
86         }, {
87                 .fourcc         = V4L2_PIX_FMT_Y10,
88         }, {
89                 .fourcc         = V4L2_PIX_FMT_Y16,
90         }, {
91                 .fourcc         = V4L2_PIX_FMT_SBGGR8,
92                 .raw            = true,
93         }, {
94                 .fourcc         = V4L2_PIX_FMT_SGBRG8,
95                 .raw            = true,
96         }, {
97                 .fourcc         = V4L2_PIX_FMT_SGRBG8,
98                 .raw            = true,
99         }, {
100                 .fourcc         = V4L2_PIX_FMT_SRGGB8,
101                 .raw            = true,
102         }, {
103                 .fourcc         = V4L2_PIX_FMT_SBGGR10,
104                 .raw            = true,
105         }, {
106                 .fourcc         = V4L2_PIX_FMT_SGBRG10,
107                 .raw            = true,
108         }, {
109                 .fourcc         = V4L2_PIX_FMT_SGRBG10,
110                 .raw            = true,
111         }, {
112                 .fourcc         = V4L2_PIX_FMT_SRGGB10,
113                 .raw            = true,
114         }, {
115                 .fourcc         = V4L2_PIX_FMT_SBGGR12,
116                 .raw            = true,
117         }, {
118                 .fourcc         = V4L2_PIX_FMT_SGBRG12,
119                 .raw            = true,
120         }, {
121                 .fourcc         = V4L2_PIX_FMT_SGRBG12,
122                 .raw            = true,
123         }, {
124                 .fourcc         = V4L2_PIX_FMT_SRGGB12,
125                 .raw            = true,
126         },
127 };
128
129 /* This is a list of formats that the ISC can receive as *input* */
130 static struct isc_format sama7g5_formats_list[] = {
131         {
132                 .fourcc         = V4L2_PIX_FMT_SBGGR8,
133                 .mbus_code      = MEDIA_BUS_FMT_SBGGR8_1X8,
134                 .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
135                 .cfa_baycfg     = ISC_BAY_CFG_BGBG,
136         },
137         {
138                 .fourcc         = V4L2_PIX_FMT_SGBRG8,
139                 .mbus_code      = MEDIA_BUS_FMT_SGBRG8_1X8,
140                 .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
141                 .cfa_baycfg     = ISC_BAY_CFG_GBGB,
142         },
143         {
144                 .fourcc         = V4L2_PIX_FMT_SGRBG8,
145                 .mbus_code      = MEDIA_BUS_FMT_SGRBG8_1X8,
146                 .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
147                 .cfa_baycfg     = ISC_BAY_CFG_GRGR,
148         },
149         {
150                 .fourcc         = V4L2_PIX_FMT_SRGGB8,
151                 .mbus_code      = MEDIA_BUS_FMT_SRGGB8_1X8,
152                 .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
153                 .cfa_baycfg     = ISC_BAY_CFG_RGRG,
154         },
155         {
156                 .fourcc         = V4L2_PIX_FMT_SBGGR10,
157                 .mbus_code      = MEDIA_BUS_FMT_SBGGR10_1X10,
158                 .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TEN,
159                 .cfa_baycfg     = ISC_BAY_CFG_RGRG,
160         },
161         {
162                 .fourcc         = V4L2_PIX_FMT_SGBRG10,
163                 .mbus_code      = MEDIA_BUS_FMT_SGBRG10_1X10,
164                 .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TEN,
165                 .cfa_baycfg     = ISC_BAY_CFG_GBGB,
166         },
167         {
168                 .fourcc         = V4L2_PIX_FMT_SGRBG10,
169                 .mbus_code      = MEDIA_BUS_FMT_SGRBG10_1X10,
170                 .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TEN,
171                 .cfa_baycfg     = ISC_BAY_CFG_GRGR,
172         },
173         {
174                 .fourcc         = V4L2_PIX_FMT_SRGGB10,
175                 .mbus_code      = MEDIA_BUS_FMT_SRGGB10_1X10,
176                 .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TEN,
177                 .cfa_baycfg     = ISC_BAY_CFG_RGRG,
178         },
179         {
180                 .fourcc         = V4L2_PIX_FMT_SBGGR12,
181                 .mbus_code      = MEDIA_BUS_FMT_SBGGR12_1X12,
182                 .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TWELVE,
183                 .cfa_baycfg     = ISC_BAY_CFG_BGBG,
184         },
185         {
186                 .fourcc         = V4L2_PIX_FMT_SGBRG12,
187                 .mbus_code      = MEDIA_BUS_FMT_SGBRG12_1X12,
188                 .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TWELVE,
189                 .cfa_baycfg     = ISC_BAY_CFG_GBGB,
190         },
191         {
192                 .fourcc         = V4L2_PIX_FMT_SGRBG12,
193                 .mbus_code      = MEDIA_BUS_FMT_SGRBG12_1X12,
194                 .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TWELVE,
195                 .cfa_baycfg     = ISC_BAY_CFG_GRGR,
196         },
197         {
198                 .fourcc         = V4L2_PIX_FMT_SRGGB12,
199                 .mbus_code      = MEDIA_BUS_FMT_SRGGB12_1X12,
200                 .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TWELVE,
201                 .cfa_baycfg     = ISC_BAY_CFG_RGRG,
202         },
203         {
204                 .fourcc         = V4L2_PIX_FMT_GREY,
205                 .mbus_code      = MEDIA_BUS_FMT_Y8_1X8,
206                 .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
207         },
208         {
209                 .fourcc         = V4L2_PIX_FMT_YUYV,
210                 .mbus_code      = MEDIA_BUS_FMT_YUYV8_2X8,
211                 .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
212         },
213         {
214                 .fourcc         = V4L2_PIX_FMT_UYVY,
215                 .mbus_code      = MEDIA_BUS_FMT_UYVY8_2X8,
216                 .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
217         },
218         {
219                 .fourcc         = V4L2_PIX_FMT_RGB565,
220                 .mbus_code      = MEDIA_BUS_FMT_RGB565_2X8_LE,
221                 .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
222         },
223         {
224                 .fourcc         = V4L2_PIX_FMT_Y10,
225                 .mbus_code      = MEDIA_BUS_FMT_Y10_1X10,
226                 .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TEN,
227         },
228 };
229
230 static void isc_sama7g5_config_csc(struct isc_device *isc)
231 {
232         struct regmap *regmap = isc->regmap;
233
234         /* Convert RGB to YUV */
235         regmap_write(regmap, ISC_CSC_YR_YG + isc->offsets.csc,
236                      0x42 | (0x81 << 16));
237         regmap_write(regmap, ISC_CSC_YB_OY + isc->offsets.csc,
238                      0x19 | (0x10 << 16));
239         regmap_write(regmap, ISC_CSC_CBR_CBG + isc->offsets.csc,
240                      0xFDA | (0xFB6 << 16));
241         regmap_write(regmap, ISC_CSC_CBB_OCB + isc->offsets.csc,
242                      0x70 | (0x80 << 16));
243         regmap_write(regmap, ISC_CSC_CRR_CRG + isc->offsets.csc,
244                      0x70 | (0xFA2 << 16));
245         regmap_write(regmap, ISC_CSC_CRB_OCR + isc->offsets.csc,
246                      0xFEE | (0x80 << 16));
247 }
248
249 static void isc_sama7g5_config_cbc(struct isc_device *isc)
250 {
251         struct regmap *regmap = isc->regmap;
252
253         /* Configure what is set via v4l2 ctrls */
254         regmap_write(regmap, ISC_CBC_BRIGHT + isc->offsets.cbc, isc->ctrls.brightness);
255         regmap_write(regmap, ISC_CBC_CONTRAST + isc->offsets.cbc, isc->ctrls.contrast);
256         /* Configure Hue and Saturation as neutral midpoint */
257         regmap_write(regmap, ISC_CBCHS_HUE, 0);
258         regmap_write(regmap, ISC_CBCHS_SAT, (1 << 4));
259 }
260
261 static void isc_sama7g5_config_cc(struct isc_device *isc)
262 {
263         struct regmap *regmap = isc->regmap;
264
265         /* Configure each register at the neutral fixed point 1.0 or 0.0 */
266         regmap_write(regmap, ISC_CC_RR_RG, (1 << 8));
267         regmap_write(regmap, ISC_CC_RB_OR, 0);
268         regmap_write(regmap, ISC_CC_GR_GG, (1 << 8) << 16);
269         regmap_write(regmap, ISC_CC_GB_OG, 0);
270         regmap_write(regmap, ISC_CC_BR_BG, 0);
271         regmap_write(regmap, ISC_CC_BB_OB, (1 << 8));
272 }
273
274 static void isc_sama7g5_config_ctrls(struct isc_device *isc,
275                                      const struct v4l2_ctrl_ops *ops)
276 {
277         struct isc_ctrls *ctrls = &isc->ctrls;
278         struct v4l2_ctrl_handler *hdl = &ctrls->handler;
279
280         ctrls->contrast = 16;
281
282         v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -2048, 2047, 1, 16);
283 }
284
285 static void isc_sama7g5_config_dpc(struct isc_device *isc)
286 {
287         u32 bay_cfg = isc->config.sd_format->cfa_baycfg;
288         struct regmap *regmap = isc->regmap;
289
290         regmap_update_bits(regmap, ISC_DPC_CFG, ISC_DPC_CFG_BLOFF_MASK,
291                            (64 << ISC_DPC_CFG_BLOFF_SHIFT));
292         regmap_update_bits(regmap, ISC_DPC_CFG, ISC_DPC_CFG_BAYCFG_MASK,
293                            (bay_cfg << ISC_DPC_CFG_BAYCFG_SHIFT));
294 }
295
296 static void isc_sama7g5_config_gam(struct isc_device *isc)
297 {
298         struct regmap *regmap = isc->regmap;
299
300         regmap_update_bits(regmap, ISC_GAM_CTRL, ISC_GAM_CTRL_BIPART,
301                            ISC_GAM_CTRL_BIPART);
302 }
303
304 static void isc_sama7g5_config_rlp(struct isc_device *isc)
305 {
306         struct regmap *regmap = isc->regmap;
307         u32 rlp_mode = isc->config.rlp_cfg_mode;
308
309         regmap_update_bits(regmap, ISC_RLP_CFG + isc->offsets.rlp,
310                            ISC_RLP_CFG_MODE_MASK | ISC_RLP_CFG_LSH |
311                            ISC_RLP_CFG_YMODE_MASK, rlp_mode);
312 }
313
314 static void isc_sama7g5_adapt_pipeline(struct isc_device *isc)
315 {
316         isc->try_config.bits_pipeline &= ISC_SAMA7G5_PIPELINE;
317 }
318
319 /* Gamma table with gamma 1/2.2 */
320 static const u32 isc_sama7g5_gamma_table[][GAMMA_ENTRIES] = {
321         /* index 0 --> gamma bipartite */
322         {
323               0x980,  0x4c0320,  0x650260,  0x7801e0,  0x8701a0,  0x940180,
324            0xa00160,  0xab0120,  0xb40120,  0xbd0120,  0xc60100,  0xce0100,
325            0xd600e0,  0xdd00e0,  0xe400e0,  0xeb00c0,  0xf100c0,  0xf700c0,
326            0xfd00c0, 0x10300a0, 0x10800c0, 0x10e00a0, 0x11300a0, 0x11800a0,
327           0x11d00a0, 0x12200a0, 0x12700a0, 0x12c0080, 0x13000a0, 0x1350080,
328           0x13900a0, 0x13e0080, 0x1420076, 0x17d0062, 0x1ae0054, 0x1d8004a,
329           0x1fd0044, 0x21f003e, 0x23e003a, 0x25b0036, 0x2760032, 0x28f0030,
330           0x2a7002e, 0x2be002c, 0x2d4002c, 0x2ea0028, 0x2fe0028, 0x3120026,
331           0x3250024, 0x3370024, 0x3490022, 0x35a0022, 0x36b0020, 0x37b0020,
332           0x38b0020, 0x39b001e, 0x3aa001e, 0x3b9001c, 0x3c7001c, 0x3d5001c,
333           0x3e3001c, 0x3f1001c, 0x3ff001a, 0x40c001a },
334 };
335
336 static int xisc_parse_dt(struct device *dev, struct isc_device *isc)
337 {
338         struct device_node *np = dev->of_node;
339         struct device_node *epn = NULL;
340         struct isc_subdev_entity *subdev_entity;
341         unsigned int flags;
342         int ret;
343         bool mipi_mode;
344
345         INIT_LIST_HEAD(&isc->subdev_entities);
346
347         mipi_mode = of_property_read_bool(np, "microchip,mipi-mode");
348
349         while (1) {
350                 struct v4l2_fwnode_endpoint v4l2_epn = { .bus_type = 0 };
351
352                 epn = of_graph_get_next_endpoint(np, epn);
353                 if (!epn)
354                         return 0;
355
356                 ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(epn),
357                                                  &v4l2_epn);
358                 if (ret) {
359                         ret = -EINVAL;
360                         dev_err(dev, "Could not parse the endpoint\n");
361                         break;
362                 }
363
364                 subdev_entity = devm_kzalloc(dev, sizeof(*subdev_entity),
365                                              GFP_KERNEL);
366                 if (!subdev_entity) {
367                         ret = -ENOMEM;
368                         break;
369                 }
370                 subdev_entity->epn = epn;
371
372                 flags = v4l2_epn.bus.parallel.flags;
373
374                 if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
375                         subdev_entity->pfe_cfg0 = ISC_PFE_CFG0_HPOL_LOW;
376
377                 if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
378                         subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_VPOL_LOW;
379
380                 if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
381                         subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_PPOL_LOW;
382
383                 if (v4l2_epn.bus_type == V4L2_MBUS_BT656)
384                         subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_CCIR_CRC |
385                                         ISC_PFE_CFG0_CCIR656;
386
387                 if (mipi_mode)
388                         subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_MIPI;
389
390                 list_add_tail(&subdev_entity->list, &isc->subdev_entities);
391         }
392         of_node_put(epn);
393
394         return ret;
395 }
396
397 static int microchip_xisc_probe(struct platform_device *pdev)
398 {
399         struct device *dev = &pdev->dev;
400         struct isc_device *isc;
401         void __iomem *io_base;
402         struct isc_subdev_entity *subdev_entity;
403         int irq;
404         int ret;
405         u32 ver;
406
407         isc = devm_kzalloc(dev, sizeof(*isc), GFP_KERNEL);
408         if (!isc)
409                 return -ENOMEM;
410
411         platform_set_drvdata(pdev, isc);
412         isc->dev = dev;
413
414         io_base = devm_platform_ioremap_resource(pdev, 0);
415         if (IS_ERR(io_base))
416                 return PTR_ERR(io_base);
417
418         isc->regmap = devm_regmap_init_mmio(dev, io_base, &microchip_isc_regmap_config);
419         if (IS_ERR(isc->regmap)) {
420                 ret = PTR_ERR(isc->regmap);
421                 dev_err(dev, "failed to init register map: %d\n", ret);
422                 return ret;
423         }
424
425         irq = platform_get_irq(pdev, 0);
426         if (irq < 0)
427                 return irq;
428
429         ret = devm_request_irq(dev, irq, microchip_isc_interrupt, 0,
430                                "microchip-sama7g5-xisc", isc);
431         if (ret < 0) {
432                 dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
433                         irq, ret);
434                 return ret;
435         }
436
437         isc->gamma_table = isc_sama7g5_gamma_table;
438         isc->gamma_max = 0;
439
440         isc->max_width = ISC_SAMA7G5_MAX_SUPPORT_WIDTH;
441         isc->max_height = ISC_SAMA7G5_MAX_SUPPORT_HEIGHT;
442
443         isc->config_dpc = isc_sama7g5_config_dpc;
444         isc->config_csc = isc_sama7g5_config_csc;
445         isc->config_cbc = isc_sama7g5_config_cbc;
446         isc->config_cc = isc_sama7g5_config_cc;
447         isc->config_gam = isc_sama7g5_config_gam;
448         isc->config_rlp = isc_sama7g5_config_rlp;
449         isc->config_ctrls = isc_sama7g5_config_ctrls;
450
451         isc->adapt_pipeline = isc_sama7g5_adapt_pipeline;
452
453         isc->offsets.csc = ISC_SAMA7G5_CSC_OFFSET;
454         isc->offsets.cbc = ISC_SAMA7G5_CBC_OFFSET;
455         isc->offsets.sub422 = ISC_SAMA7G5_SUB422_OFFSET;
456         isc->offsets.sub420 = ISC_SAMA7G5_SUB420_OFFSET;
457         isc->offsets.rlp = ISC_SAMA7G5_RLP_OFFSET;
458         isc->offsets.his = ISC_SAMA7G5_HIS_OFFSET;
459         isc->offsets.dma = ISC_SAMA7G5_DMA_OFFSET;
460         isc->offsets.version = ISC_SAMA7G5_VERSION_OFFSET;
461         isc->offsets.his_entry = ISC_SAMA7G5_HIS_ENTRY_OFFSET;
462
463         isc->controller_formats = sama7g5_controller_formats;
464         isc->controller_formats_size = ARRAY_SIZE(sama7g5_controller_formats);
465         isc->formats_list = sama7g5_formats_list;
466         isc->formats_list_size = ARRAY_SIZE(sama7g5_formats_list);
467
468         /* sama7g5-isc RAM access port is full AXI4 - 32 bits per beat */
469         isc->dcfg = ISC_DCFG_YMBSIZE_BEATS32 | ISC_DCFG_CMBSIZE_BEATS32;
470
471         /* sama7g5-isc : ISPCK does not exist, ISC is clocked by MCK */
472         isc->ispck_required = false;
473
474         ret = microchip_isc_pipeline_init(isc);
475         if (ret)
476                 return ret;
477
478         isc->hclock = devm_clk_get(dev, "hclock");
479         if (IS_ERR(isc->hclock)) {
480                 ret = PTR_ERR(isc->hclock);
481                 dev_err(dev, "failed to get hclock: %d\n", ret);
482                 return ret;
483         }
484
485         ret = clk_prepare_enable(isc->hclock);
486         if (ret) {
487                 dev_err(dev, "failed to enable hclock: %d\n", ret);
488                 return ret;
489         }
490
491         ret = microchip_isc_clk_init(isc);
492         if (ret) {
493                 dev_err(dev, "failed to init isc clock: %d\n", ret);
494                 goto unprepare_hclk;
495         }
496
497         ret = v4l2_device_register(dev, &isc->v4l2_dev);
498         if (ret) {
499                 dev_err(dev, "unable to register v4l2 device.\n");
500                 goto unprepare_hclk;
501         }
502
503         ret = xisc_parse_dt(dev, isc);
504         if (ret) {
505                 dev_err(dev, "fail to parse device tree\n");
506                 goto unregister_v4l2_device;
507         }
508
509         if (list_empty(&isc->subdev_entities)) {
510                 dev_err(dev, "no subdev found\n");
511                 ret = -ENODEV;
512                 goto unregister_v4l2_device;
513         }
514
515         list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
516                 struct v4l2_async_connection *asd;
517                 struct fwnode_handle *fwnode =
518                         of_fwnode_handle(subdev_entity->epn);
519
520                 v4l2_async_nf_init(&subdev_entity->notifier, &isc->v4l2_dev);
521
522                 asd = v4l2_async_nf_add_fwnode_remote(&subdev_entity->notifier,
523                                                       fwnode,
524                                                       struct v4l2_async_connection);
525
526                 of_node_put(subdev_entity->epn);
527                 subdev_entity->epn = NULL;
528
529                 if (IS_ERR(asd)) {
530                         ret = PTR_ERR(asd);
531                         goto cleanup_subdev;
532                 }
533
534                 subdev_entity->notifier.ops = &microchip_isc_async_ops;
535
536                 ret = v4l2_async_nf_register(&subdev_entity->notifier);
537                 if (ret) {
538                         dev_err(dev, "fail to register async notifier\n");
539                         goto cleanup_subdev;
540                 }
541
542                 if (video_is_registered(&isc->video_dev))
543                         break;
544         }
545
546         regmap_read(isc->regmap, ISC_VERSION + isc->offsets.version, &ver);
547
548         ret = isc_mc_init(isc, ver);
549         if (ret < 0)
550                 goto isc_probe_mc_init_err;
551
552         pm_runtime_set_active(dev);
553         pm_runtime_enable(dev);
554         pm_request_idle(dev);
555
556         dev_info(dev, "Microchip XISC version %x\n", ver);
557
558         return 0;
559
560 isc_probe_mc_init_err:
561         isc_mc_cleanup(isc);
562
563 cleanup_subdev:
564         microchip_isc_subdev_cleanup(isc);
565
566 unregister_v4l2_device:
567         v4l2_device_unregister(&isc->v4l2_dev);
568
569 unprepare_hclk:
570         clk_disable_unprepare(isc->hclock);
571
572         microchip_isc_clk_cleanup(isc);
573
574         return ret;
575 }
576
577 static void microchip_xisc_remove(struct platform_device *pdev)
578 {
579         struct isc_device *isc = platform_get_drvdata(pdev);
580
581         pm_runtime_disable(&pdev->dev);
582
583         isc_mc_cleanup(isc);
584
585         microchip_isc_subdev_cleanup(isc);
586
587         v4l2_device_unregister(&isc->v4l2_dev);
588
589         clk_disable_unprepare(isc->hclock);
590
591         microchip_isc_clk_cleanup(isc);
592 }
593
594 static int __maybe_unused xisc_runtime_suspend(struct device *dev)
595 {
596         struct isc_device *isc = dev_get_drvdata(dev);
597
598         clk_disable_unprepare(isc->hclock);
599
600         return 0;
601 }
602
603 static int __maybe_unused xisc_runtime_resume(struct device *dev)
604 {
605         struct isc_device *isc = dev_get_drvdata(dev);
606         int ret;
607
608         ret = clk_prepare_enable(isc->hclock);
609         if (ret)
610                 return ret;
611
612         return ret;
613 }
614
615 static const struct dev_pm_ops microchip_xisc_dev_pm_ops = {
616         SET_RUNTIME_PM_OPS(xisc_runtime_suspend, xisc_runtime_resume, NULL)
617 };
618
619 #if IS_ENABLED(CONFIG_OF)
620 static const struct of_device_id microchip_xisc_of_match[] = {
621         { .compatible = "microchip,sama7g5-isc" },
622         { }
623 };
624 MODULE_DEVICE_TABLE(of, microchip_xisc_of_match);
625 #endif
626
627 static struct platform_driver microchip_xisc_driver = {
628         .probe  = microchip_xisc_probe,
629         .remove_new = microchip_xisc_remove,
630         .driver = {
631                 .name           = "microchip-sama7g5-xisc",
632                 .pm             = &microchip_xisc_dev_pm_ops,
633                 .of_match_table = of_match_ptr(microchip_xisc_of_match),
634         },
635 };
636
637 module_platform_driver(microchip_xisc_driver);
638
639 MODULE_AUTHOR("Eugen Hristev <eugen.hristev@microchip.com>");
640 MODULE_DESCRIPTION("The V4L2 driver for Microchip-XISC");
641 MODULE_LICENSE("GPL v2");