xref: /linux/drivers/media/platform/microchip/microchip-sama7g5-isc.c (revision 34dc1baba215b826e454b8d19e4f24adbeb7d00d)
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");
642