1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Microchip Image Sensor Controller (ISC) driver
4  *
5  * Copyright (C) 2016-2019 Microchip Technology, Inc.
6  *
7  * Author: Songjun Wu
8  * Author: Eugen Hristev <eugen.hristev@microchip.com>
9  *
10  *
11  * Sensor-->PFE-->WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB-->RLP-->DMA
12  *
13  * ISC video pipeline integrates the following submodules:
14  * PFE: Parallel Front End to sample the camera sensor input stream
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  * CSC: Programmable color space conversion
20  * CBC: Contrast and Brightness control
21  * SUB: This module performs YCbCr444 to YCbCr420 chrominance subsampling
22  * RLP: This module performs rounding, range limiting
23  *      and packing of the incoming data
24  */
25 
26 #include <linux/clk.h>
27 #include <linux/clkdev.h>
28 #include <linux/clk-provider.h>
29 #include <linux/delay.h>
30 #include <linux/interrupt.h>
31 #include <linux/math64.h>
32 #include <linux/module.h>
33 #include <linux/of.h>
34 #include <linux/of_graph.h>
35 #include <linux/platform_device.h>
36 #include <linux/pm_runtime.h>
37 #include <linux/regmap.h>
38 #include <linux/videodev2.h>
39 
40 #include <media/v4l2-ctrls.h>
41 #include <media/v4l2-device.h>
42 #include <media/v4l2-event.h>
43 #include <media/v4l2-image-sizes.h>
44 #include <media/v4l2-ioctl.h>
45 #include <media/v4l2-fwnode.h>
46 #include <media/v4l2-subdev.h>
47 #include <media/videobuf2-dma-contig.h>
48 
49 #include "atmel-isc-regs.h"
50 #include "atmel-isc.h"
51 
52 #define ISC_SAMA5D2_MAX_SUPPORT_WIDTH   2592
53 #define ISC_SAMA5D2_MAX_SUPPORT_HEIGHT  1944
54 
55 #define ISC_SAMA5D2_PIPELINE \
56 	(WB_ENABLE | CFA_ENABLE | CC_ENABLE | GAM_ENABLES | CSC_ENABLE | \
57 	CBC_ENABLE | SUB422_ENABLE | SUB420_ENABLE)
58 
59 /* This is a list of the formats that the ISC can *output* */
60 static const struct isc_format sama5d2_controller_formats[] = {
61 	{
62 		.fourcc		= V4L2_PIX_FMT_ARGB444,
63 	}, {
64 		.fourcc		= V4L2_PIX_FMT_ARGB555,
65 	}, {
66 		.fourcc		= V4L2_PIX_FMT_RGB565,
67 	}, {
68 		.fourcc		= V4L2_PIX_FMT_ABGR32,
69 	}, {
70 		.fourcc		= V4L2_PIX_FMT_XBGR32,
71 	}, {
72 		.fourcc		= V4L2_PIX_FMT_YUV420,
73 	}, {
74 		.fourcc		= V4L2_PIX_FMT_YUYV,
75 	}, {
76 		.fourcc		= V4L2_PIX_FMT_YUV422P,
77 	}, {
78 		.fourcc		= V4L2_PIX_FMT_GREY,
79 	}, {
80 		.fourcc		= V4L2_PIX_FMT_Y10,
81 	}, {
82 		.fourcc		= V4L2_PIX_FMT_SBGGR8,
83 	}, {
84 		.fourcc		= V4L2_PIX_FMT_SGBRG8,
85 	}, {
86 		.fourcc		= V4L2_PIX_FMT_SGRBG8,
87 	}, {
88 		.fourcc		= V4L2_PIX_FMT_SRGGB8,
89 	}, {
90 		.fourcc		= V4L2_PIX_FMT_SBGGR10,
91 	}, {
92 		.fourcc		= V4L2_PIX_FMT_SGBRG10,
93 	}, {
94 		.fourcc		= V4L2_PIX_FMT_SGRBG10,
95 	}, {
96 		.fourcc		= V4L2_PIX_FMT_SRGGB10,
97 	},
98 };
99 
100 /* This is a list of formats that the ISC can receive as *input* */
101 static struct isc_format sama5d2_formats_list[] = {
102 	{
103 		.fourcc		= V4L2_PIX_FMT_SBGGR8,
104 		.mbus_code	= MEDIA_BUS_FMT_SBGGR8_1X8,
105 		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,
106 		.cfa_baycfg	= ISC_BAY_CFG_BGBG,
107 	},
108 	{
109 		.fourcc		= V4L2_PIX_FMT_SGBRG8,
110 		.mbus_code	= MEDIA_BUS_FMT_SGBRG8_1X8,
111 		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,
112 		.cfa_baycfg	= ISC_BAY_CFG_GBGB,
113 	},
114 	{
115 		.fourcc		= V4L2_PIX_FMT_SGRBG8,
116 		.mbus_code	= MEDIA_BUS_FMT_SGRBG8_1X8,
117 		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,
118 		.cfa_baycfg	= ISC_BAY_CFG_GRGR,
119 	},
120 	{
121 		.fourcc		= V4L2_PIX_FMT_SRGGB8,
122 		.mbus_code	= MEDIA_BUS_FMT_SRGGB8_1X8,
123 		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,
124 		.cfa_baycfg	= ISC_BAY_CFG_RGRG,
125 	},
126 	{
127 		.fourcc		= V4L2_PIX_FMT_SBGGR10,
128 		.mbus_code	= MEDIA_BUS_FMT_SBGGR10_1X10,
129 		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TEN,
130 		.cfa_baycfg	= ISC_BAY_CFG_RGRG,
131 	},
132 	{
133 		.fourcc		= V4L2_PIX_FMT_SGBRG10,
134 		.mbus_code	= MEDIA_BUS_FMT_SGBRG10_1X10,
135 		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TEN,
136 		.cfa_baycfg	= ISC_BAY_CFG_GBGB,
137 	},
138 	{
139 		.fourcc		= V4L2_PIX_FMT_SGRBG10,
140 		.mbus_code	= MEDIA_BUS_FMT_SGRBG10_1X10,
141 		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TEN,
142 		.cfa_baycfg	= ISC_BAY_CFG_GRGR,
143 	},
144 	{
145 		.fourcc		= V4L2_PIX_FMT_SRGGB10,
146 		.mbus_code	= MEDIA_BUS_FMT_SRGGB10_1X10,
147 		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TEN,
148 		.cfa_baycfg	= ISC_BAY_CFG_RGRG,
149 	},
150 	{
151 		.fourcc		= V4L2_PIX_FMT_SBGGR12,
152 		.mbus_code	= MEDIA_BUS_FMT_SBGGR12_1X12,
153 		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TWELVE,
154 		.cfa_baycfg	= ISC_BAY_CFG_BGBG,
155 	},
156 	{
157 		.fourcc		= V4L2_PIX_FMT_SGBRG12,
158 		.mbus_code	= MEDIA_BUS_FMT_SGBRG12_1X12,
159 		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TWELVE,
160 		.cfa_baycfg	= ISC_BAY_CFG_GBGB,
161 	},
162 	{
163 		.fourcc		= V4L2_PIX_FMT_SGRBG12,
164 		.mbus_code	= MEDIA_BUS_FMT_SGRBG12_1X12,
165 		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TWELVE,
166 		.cfa_baycfg	= ISC_BAY_CFG_GRGR,
167 	},
168 	{
169 		.fourcc		= V4L2_PIX_FMT_SRGGB12,
170 		.mbus_code	= MEDIA_BUS_FMT_SRGGB12_1X12,
171 		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TWELVE,
172 		.cfa_baycfg	= ISC_BAY_CFG_RGRG,
173 	},
174 	{
175 		.fourcc		= V4L2_PIX_FMT_GREY,
176 		.mbus_code	= MEDIA_BUS_FMT_Y8_1X8,
177 		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,
178 	},
179 	{
180 		.fourcc		= V4L2_PIX_FMT_YUYV,
181 		.mbus_code	= MEDIA_BUS_FMT_YUYV8_2X8,
182 		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,
183 	},
184 	{
185 		.fourcc		= V4L2_PIX_FMT_RGB565,
186 		.mbus_code	= MEDIA_BUS_FMT_RGB565_2X8_LE,
187 		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,
188 	},
189 	{
190 		.fourcc		= V4L2_PIX_FMT_Y10,
191 		.mbus_code	= MEDIA_BUS_FMT_Y10_1X10,
192 		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TEN,
193 	},
194 
195 };
196 
197 static void isc_sama5d2_config_csc(struct isc_device *isc)
198 {
199 	struct regmap *regmap = isc->regmap;
200 
201 	/* Convert RGB to YUV */
202 	regmap_write(regmap, ISC_CSC_YR_YG + isc->offsets.csc,
203 		     0x42 | (0x81 << 16));
204 	regmap_write(regmap, ISC_CSC_YB_OY + isc->offsets.csc,
205 		     0x19 | (0x10 << 16));
206 	regmap_write(regmap, ISC_CSC_CBR_CBG + isc->offsets.csc,
207 		     0xFDA | (0xFB6 << 16));
208 	regmap_write(regmap, ISC_CSC_CBB_OCB + isc->offsets.csc,
209 		     0x70 | (0x80 << 16));
210 	regmap_write(regmap, ISC_CSC_CRR_CRG + isc->offsets.csc,
211 		     0x70 | (0xFA2 << 16));
212 	regmap_write(regmap, ISC_CSC_CRB_OCR + isc->offsets.csc,
213 		     0xFEE | (0x80 << 16));
214 }
215 
216 static void isc_sama5d2_config_cbc(struct isc_device *isc)
217 {
218 	struct regmap *regmap = isc->regmap;
219 
220 	regmap_write(regmap, ISC_CBC_BRIGHT + isc->offsets.cbc,
221 		     isc->ctrls.brightness);
222 	regmap_write(regmap, ISC_CBC_CONTRAST + isc->offsets.cbc,
223 		     isc->ctrls.contrast);
224 }
225 
226 static void isc_sama5d2_config_cc(struct isc_device *isc)
227 {
228 	struct regmap *regmap = isc->regmap;
229 
230 	/* Configure each register at the neutral fixed point 1.0 or 0.0 */
231 	regmap_write(regmap, ISC_CC_RR_RG, (1 << 8));
232 	regmap_write(regmap, ISC_CC_RB_OR, 0);
233 	regmap_write(regmap, ISC_CC_GR_GG, (1 << 8) << 16);
234 	regmap_write(regmap, ISC_CC_GB_OG, 0);
235 	regmap_write(regmap, ISC_CC_BR_BG, 0);
236 	regmap_write(regmap, ISC_CC_BB_OB, (1 << 8));
237 }
238 
239 static void isc_sama5d2_config_ctrls(struct isc_device *isc,
240 				     const struct v4l2_ctrl_ops *ops)
241 {
242 	struct isc_ctrls *ctrls = &isc->ctrls;
243 	struct v4l2_ctrl_handler *hdl = &ctrls->handler;
244 
245 	ctrls->contrast = 256;
246 
247 	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -2048, 2047, 1, 256);
248 }
249 
250 static void isc_sama5d2_config_dpc(struct isc_device *isc)
251 {
252 	/* This module is not present on sama5d2 pipeline */
253 }
254 
255 static void isc_sama5d2_config_gam(struct isc_device *isc)
256 {
257 	/* No specific gamma configuration */
258 }
259 
260 static void isc_sama5d2_config_rlp(struct isc_device *isc)
261 {
262 	struct regmap *regmap = isc->regmap;
263 	u32 rlp_mode = isc->config.rlp_cfg_mode;
264 
265 	/*
266 	 * In sama5d2, the YUV planar modes and the YUYV modes are treated
267 	 * in the same way in RLP register.
268 	 * Normally, YYCC mode should be Luma(n) - Color B(n) - Color R (n)
269 	 * and YCYC should be Luma(n + 1) - Color B (n) - Luma (n) - Color R (n)
270 	 * but in sama5d2, the YCYC mode does not exist, and YYCC must be
271 	 * selected for both planar and interleaved modes, as in fact
272 	 * both modes are supported.
273 	 *
274 	 * Thus, if the YCYC mode is selected, replace it with the
275 	 * sama5d2-compliant mode which is YYCC .
276 	 */
277 	if ((rlp_mode & ISC_RLP_CFG_MODE_MASK) == ISC_RLP_CFG_MODE_YCYC) {
278 		rlp_mode &= ~ISC_RLP_CFG_MODE_MASK;
279 		rlp_mode |= ISC_RLP_CFG_MODE_YYCC;
280 	}
281 
282 	regmap_update_bits(regmap, ISC_RLP_CFG + isc->offsets.rlp,
283 			   ISC_RLP_CFG_MODE_MASK, rlp_mode);
284 }
285 
286 static void isc_sama5d2_adapt_pipeline(struct isc_device *isc)
287 {
288 	isc->try_config.bits_pipeline &= ISC_SAMA5D2_PIPELINE;
289 }
290 
291 /* Gamma table with gamma 1/2.2 */
292 static const u32 isc_sama5d2_gamma_table[][GAMMA_ENTRIES] = {
293 	/* 0 --> gamma 1/1.8 */
294 	{      0x65,  0x66002F,  0x950025,  0xBB0020,  0xDB001D,  0xF8001A,
295 	  0x1130018, 0x12B0017, 0x1420016, 0x1580014, 0x16D0013, 0x1810012,
296 	  0x1940012, 0x1A60012, 0x1B80011, 0x1C90010, 0x1DA0010, 0x1EA000F,
297 	  0x1FA000F, 0x209000F, 0x218000F, 0x227000E, 0x235000E, 0x243000E,
298 	  0x251000E, 0x25F000D, 0x26C000D, 0x279000D, 0x286000D, 0x293000C,
299 	  0x2A0000C, 0x2AC000C, 0x2B8000C, 0x2C4000C, 0x2D0000B, 0x2DC000B,
300 	  0x2E7000B, 0x2F3000B, 0x2FE000B, 0x309000B, 0x314000B, 0x31F000A,
301 	  0x32A000A, 0x334000B, 0x33F000A, 0x349000A, 0x354000A, 0x35E000A,
302 	  0x368000A, 0x372000A, 0x37C000A, 0x386000A, 0x3900009, 0x399000A,
303 	  0x3A30009, 0x3AD0009, 0x3B60009, 0x3BF000A, 0x3C90009, 0x3D20009,
304 	  0x3DB0009, 0x3E40009, 0x3ED0009, 0x3F60009 },
305 
306 	/* 1 --> gamma 1/2 */
307 	{      0x7F,  0x800034,  0xB50028,  0xDE0021, 0x100001E, 0x11E001B,
308 	  0x1390019, 0x1520017, 0x16A0015, 0x1800014, 0x1940014, 0x1A80013,
309 	  0x1BB0012, 0x1CD0011, 0x1DF0010, 0x1EF0010, 0x200000F, 0x20F000F,
310 	  0x21F000E, 0x22D000F, 0x23C000E, 0x24A000E, 0x258000D, 0x265000D,
311 	  0x273000C, 0x27F000D, 0x28C000C, 0x299000C, 0x2A5000C, 0x2B1000B,
312 	  0x2BC000C, 0x2C8000B, 0x2D3000C, 0x2DF000B, 0x2EA000A, 0x2F5000A,
313 	  0x2FF000B, 0x30A000A, 0x314000B, 0x31F000A, 0x329000A, 0x333000A,
314 	  0x33D0009, 0x3470009, 0x350000A, 0x35A0009, 0x363000A, 0x36D0009,
315 	  0x3760009, 0x37F0009, 0x3880009, 0x3910009, 0x39A0009, 0x3A30009,
316 	  0x3AC0008, 0x3B40009, 0x3BD0008, 0x3C60008, 0x3CE0008, 0x3D60009,
317 	  0x3DF0008, 0x3E70008, 0x3EF0008, 0x3F70008 },
318 
319 	/* 2 --> gamma 1/2.2 */
320 	{      0x99,  0x9B0038,  0xD4002A,  0xFF0023, 0x122001F, 0x141001B,
321 	  0x15D0019, 0x1760017, 0x18E0015, 0x1A30015, 0x1B80013, 0x1CC0012,
322 	  0x1DE0011, 0x1F00010, 0x2010010, 0x2110010, 0x221000F, 0x230000F,
323 	  0x23F000E, 0x24D000E, 0x25B000D, 0x269000C, 0x276000C, 0x283000C,
324 	  0x28F000C, 0x29B000C, 0x2A7000C, 0x2B3000B, 0x2BF000B, 0x2CA000B,
325 	  0x2D5000B, 0x2E0000A, 0x2EB000A, 0x2F5000A, 0x2FF000A, 0x30A000A,
326 	  0x3140009, 0x31E0009, 0x327000A, 0x3310009, 0x33A0009, 0x3440009,
327 	  0x34D0009, 0x3560009, 0x35F0009, 0x3680008, 0x3710008, 0x3790009,
328 	  0x3820008, 0x38A0008, 0x3930008, 0x39B0008, 0x3A30008, 0x3AB0008,
329 	  0x3B30008, 0x3BB0008, 0x3C30008, 0x3CB0007, 0x3D20008, 0x3DA0007,
330 	  0x3E20007, 0x3E90007, 0x3F00008, 0x3F80007 },
331 };
332 
333 static int isc_parse_dt(struct device *dev, struct isc_device *isc)
334 {
335 	struct device_node *np = dev->of_node;
336 	struct device_node *epn = NULL;
337 	struct isc_subdev_entity *subdev_entity;
338 	unsigned int flags;
339 	int ret;
340 
341 	INIT_LIST_HEAD(&isc->subdev_entities);
342 
343 	while (1) {
344 		struct v4l2_fwnode_endpoint v4l2_epn = { .bus_type = 0 };
345 
346 		epn = of_graph_get_next_endpoint(np, epn);
347 		if (!epn)
348 			return 0;
349 
350 		ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(epn),
351 						 &v4l2_epn);
352 		if (ret) {
353 			ret = -EINVAL;
354 			dev_err(dev, "Could not parse the endpoint\n");
355 			break;
356 		}
357 
358 		subdev_entity = devm_kzalloc(dev, sizeof(*subdev_entity),
359 					     GFP_KERNEL);
360 		if (!subdev_entity) {
361 			ret = -ENOMEM;
362 			break;
363 		}
364 		subdev_entity->epn = epn;
365 
366 		flags = v4l2_epn.bus.parallel.flags;
367 
368 		if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
369 			subdev_entity->pfe_cfg0 = ISC_PFE_CFG0_HPOL_LOW;
370 
371 		if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
372 			subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_VPOL_LOW;
373 
374 		if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
375 			subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_PPOL_LOW;
376 
377 		if (v4l2_epn.bus_type == V4L2_MBUS_BT656)
378 			subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_CCIR_CRC |
379 					ISC_PFE_CFG0_CCIR656;
380 
381 		list_add_tail(&subdev_entity->list, &isc->subdev_entities);
382 	}
383 	of_node_put(epn);
384 
385 	return ret;
386 }
387 
388 static int atmel_isc_probe(struct platform_device *pdev)
389 {
390 	struct device *dev = &pdev->dev;
391 	struct isc_device *isc;
392 	struct resource *res;
393 	void __iomem *io_base;
394 	struct isc_subdev_entity *subdev_entity;
395 	int irq;
396 	int ret;
397 	u32 ver;
398 
399 	isc = devm_kzalloc(dev, sizeof(*isc), GFP_KERNEL);
400 	if (!isc)
401 		return -ENOMEM;
402 
403 	platform_set_drvdata(pdev, isc);
404 	isc->dev = dev;
405 
406 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
407 	io_base = devm_ioremap_resource(dev, res);
408 	if (IS_ERR(io_base))
409 		return PTR_ERR(io_base);
410 
411 	isc->regmap = devm_regmap_init_mmio(dev, io_base, &atmel_isc_regmap_config);
412 	if (IS_ERR(isc->regmap)) {
413 		ret = PTR_ERR(isc->regmap);
414 		dev_err(dev, "failed to init register map: %d\n", ret);
415 		return ret;
416 	}
417 
418 	irq = platform_get_irq(pdev, 0);
419 	if (irq < 0)
420 		return irq;
421 
422 	ret = devm_request_irq(dev, irq, atmel_isc_interrupt, 0,
423 			       "atmel-sama5d2-isc", isc);
424 	if (ret < 0) {
425 		dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
426 			irq, ret);
427 		return ret;
428 	}
429 
430 	isc->gamma_table = isc_sama5d2_gamma_table;
431 	isc->gamma_max = 2;
432 
433 	isc->max_width = ISC_SAMA5D2_MAX_SUPPORT_WIDTH;
434 	isc->max_height = ISC_SAMA5D2_MAX_SUPPORT_HEIGHT;
435 
436 	isc->config_dpc = isc_sama5d2_config_dpc;
437 	isc->config_csc = isc_sama5d2_config_csc;
438 	isc->config_cbc = isc_sama5d2_config_cbc;
439 	isc->config_cc = isc_sama5d2_config_cc;
440 	isc->config_gam = isc_sama5d2_config_gam;
441 	isc->config_rlp = isc_sama5d2_config_rlp;
442 	isc->config_ctrls = isc_sama5d2_config_ctrls;
443 
444 	isc->adapt_pipeline = isc_sama5d2_adapt_pipeline;
445 
446 	isc->offsets.csc = ISC_SAMA5D2_CSC_OFFSET;
447 	isc->offsets.cbc = ISC_SAMA5D2_CBC_OFFSET;
448 	isc->offsets.sub422 = ISC_SAMA5D2_SUB422_OFFSET;
449 	isc->offsets.sub420 = ISC_SAMA5D2_SUB420_OFFSET;
450 	isc->offsets.rlp = ISC_SAMA5D2_RLP_OFFSET;
451 	isc->offsets.his = ISC_SAMA5D2_HIS_OFFSET;
452 	isc->offsets.dma = ISC_SAMA5D2_DMA_OFFSET;
453 	isc->offsets.version = ISC_SAMA5D2_VERSION_OFFSET;
454 	isc->offsets.his_entry = ISC_SAMA5D2_HIS_ENTRY_OFFSET;
455 
456 	isc->controller_formats = sama5d2_controller_formats;
457 	isc->controller_formats_size = ARRAY_SIZE(sama5d2_controller_formats);
458 	isc->formats_list = sama5d2_formats_list;
459 	isc->formats_list_size = ARRAY_SIZE(sama5d2_formats_list);
460 
461 	/* sama5d2-isc - 8 bits per beat */
462 	isc->dcfg = ISC_DCFG_YMBSIZE_BEATS8 | ISC_DCFG_CMBSIZE_BEATS8;
463 
464 	/* sama5d2-isc : ISPCK is required and mandatory */
465 	isc->ispck_required = true;
466 
467 	ret = atmel_isc_pipeline_init(isc);
468 	if (ret)
469 		return ret;
470 
471 	isc->hclock = devm_clk_get(dev, "hclock");
472 	if (IS_ERR(isc->hclock)) {
473 		ret = PTR_ERR(isc->hclock);
474 		dev_err(dev, "failed to get hclock: %d\n", ret);
475 		return ret;
476 	}
477 
478 	ret = clk_prepare_enable(isc->hclock);
479 	if (ret) {
480 		dev_err(dev, "failed to enable hclock: %d\n", ret);
481 		return ret;
482 	}
483 
484 	ret = atmel_isc_clk_init(isc);
485 	if (ret) {
486 		dev_err(dev, "failed to init isc clock: %d\n", ret);
487 		goto unprepare_hclk;
488 	}
489 	ret = v4l2_device_register(dev, &isc->v4l2_dev);
490 	if (ret) {
491 		dev_err(dev, "unable to register v4l2 device.\n");
492 		goto unprepare_clk;
493 	}
494 
495 	ret = isc_parse_dt(dev, isc);
496 	if (ret) {
497 		dev_err(dev, "fail to parse device tree\n");
498 		goto unregister_v4l2_device;
499 	}
500 
501 	if (list_empty(&isc->subdev_entities)) {
502 		dev_err(dev, "no subdev found\n");
503 		ret = -ENODEV;
504 		goto unregister_v4l2_device;
505 	}
506 
507 	list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
508 		struct v4l2_async_subdev *asd;
509 		struct fwnode_handle *fwnode =
510 			of_fwnode_handle(subdev_entity->epn);
511 
512 		v4l2_async_nf_init(&subdev_entity->notifier);
513 
514 		asd = v4l2_async_nf_add_fwnode_remote(&subdev_entity->notifier,
515 						      fwnode,
516 						      struct v4l2_async_subdev);
517 
518 		of_node_put(subdev_entity->epn);
519 		subdev_entity->epn = NULL;
520 
521 		if (IS_ERR(asd)) {
522 			ret = PTR_ERR(asd);
523 			goto cleanup_subdev;
524 		}
525 
526 		subdev_entity->notifier.ops = &atmel_isc_async_ops;
527 
528 		ret = v4l2_async_nf_register(&isc->v4l2_dev,
529 					     &subdev_entity->notifier);
530 		if (ret) {
531 			dev_err(dev, "fail to register async notifier\n");
532 			goto cleanup_subdev;
533 		}
534 
535 		if (video_is_registered(&isc->video_dev))
536 			break;
537 	}
538 
539 	pm_runtime_set_active(dev);
540 	pm_runtime_enable(dev);
541 	pm_request_idle(dev);
542 
543 	isc->ispck = isc->isc_clks[ISC_ISPCK].clk;
544 
545 	ret = clk_prepare_enable(isc->ispck);
546 	if (ret) {
547 		dev_err(dev, "failed to enable ispck: %d\n", ret);
548 		goto disable_pm;
549 	}
550 
551 	/* ispck should be greater or equal to hclock */
552 	ret = clk_set_rate(isc->ispck, clk_get_rate(isc->hclock));
553 	if (ret) {
554 		dev_err(dev, "failed to set ispck rate: %d\n", ret);
555 		goto unprepare_clk;
556 	}
557 
558 	regmap_read(isc->regmap, ISC_VERSION + isc->offsets.version, &ver);
559 	dev_info(dev, "Microchip ISC version %x\n", ver);
560 
561 	return 0;
562 
563 unprepare_clk:
564 	clk_disable_unprepare(isc->ispck);
565 
566 disable_pm:
567 	pm_runtime_disable(dev);
568 
569 cleanup_subdev:
570 	atmel_isc_subdev_cleanup(isc);
571 
572 unregister_v4l2_device:
573 	v4l2_device_unregister(&isc->v4l2_dev);
574 
575 unprepare_hclk:
576 	clk_disable_unprepare(isc->hclock);
577 
578 	atmel_isc_clk_cleanup(isc);
579 
580 	return ret;
581 }
582 
583 static int atmel_isc_remove(struct platform_device *pdev)
584 {
585 	struct isc_device *isc = platform_get_drvdata(pdev);
586 
587 	pm_runtime_disable(&pdev->dev);
588 
589 	atmel_isc_subdev_cleanup(isc);
590 
591 	v4l2_device_unregister(&isc->v4l2_dev);
592 
593 	clk_disable_unprepare(isc->ispck);
594 	clk_disable_unprepare(isc->hclock);
595 
596 	atmel_isc_clk_cleanup(isc);
597 
598 	return 0;
599 }
600 
601 static int __maybe_unused isc_runtime_suspend(struct device *dev)
602 {
603 	struct isc_device *isc = dev_get_drvdata(dev);
604 
605 	clk_disable_unprepare(isc->ispck);
606 	clk_disable_unprepare(isc->hclock);
607 
608 	return 0;
609 }
610 
611 static int __maybe_unused isc_runtime_resume(struct device *dev)
612 {
613 	struct isc_device *isc = dev_get_drvdata(dev);
614 	int ret;
615 
616 	ret = clk_prepare_enable(isc->hclock);
617 	if (ret)
618 		return ret;
619 
620 	ret = clk_prepare_enable(isc->ispck);
621 	if (ret)
622 		clk_disable_unprepare(isc->hclock);
623 
624 	return ret;
625 }
626 
627 static const struct dev_pm_ops atmel_isc_dev_pm_ops = {
628 	SET_RUNTIME_PM_OPS(isc_runtime_suspend, isc_runtime_resume, NULL)
629 };
630 
631 #if IS_ENABLED(CONFIG_OF)
632 static const struct of_device_id atmel_isc_of_match[] = {
633 	{ .compatible = "atmel,sama5d2-isc" },
634 	{ }
635 };
636 MODULE_DEVICE_TABLE(of, atmel_isc_of_match);
637 #endif
638 
639 static struct platform_driver atmel_isc_driver = {
640 	.probe	= atmel_isc_probe,
641 	.remove	= atmel_isc_remove,
642 	.driver	= {
643 		.name		= "atmel-sama5d2-isc",
644 		.pm		= &atmel_isc_dev_pm_ops,
645 		.of_match_table = of_match_ptr(atmel_isc_of_match),
646 	},
647 };
648 
649 module_platform_driver(atmel_isc_driver);
650 
651 MODULE_AUTHOR("Songjun Wu");
652 MODULE_DESCRIPTION("The V4L2 driver for Atmel-ISC");
653 MODULE_LICENSE("GPL v2");
654