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* */
63static 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* */
130static 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
230static 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
249static 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
261static 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
274static 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
285static 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
296static 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
304static 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
314static 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 */
320static 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
336static 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
397static 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
560isc_probe_mc_init_err:
561	isc_mc_cleanup(isc);
562
563cleanup_subdev:
564	microchip_isc_subdev_cleanup(isc);
565
566unregister_v4l2_device:
567	v4l2_device_unregister(&isc->v4l2_dev);
568
569unprepare_hclk:
570	clk_disable_unprepare(isc->hclock);
571
572	microchip_isc_clk_cleanup(isc);
573
574	return ret;
575}
576
577static 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
594static 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
603static 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
615static 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)
620static const struct of_device_id microchip_xisc_of_match[] = {
621	{ .compatible = "microchip,sama7g5-isc" },
622	{ }
623};
624MODULE_DEVICE_TABLE(of, microchip_xisc_of_match);
625#endif
626
627static 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
637module_platform_driver(microchip_xisc_driver);
638
639MODULE_AUTHOR("Eugen Hristev <eugen.hristev@microchip.com>");
640MODULE_DESCRIPTION("The V4L2 driver for Microchip-XISC");
641MODULE_LICENSE("GPL v2");
642