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