• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
isc_sama7g5_config_csc(struct isc_device * isc)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 
isc_sama7g5_config_cbc(struct isc_device * isc)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 
isc_sama7g5_config_cc(struct isc_device * isc)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 
isc_sama7g5_config_ctrls(struct isc_device * isc,const struct v4l2_ctrl_ops * ops)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 
isc_sama7g5_config_dpc(struct isc_device * isc)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 
isc_sama7g5_config_gam(struct isc_device * isc)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 
isc_sama7g5_config_rlp(struct isc_device * isc)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 
isc_sama7g5_adapt_pipeline(struct isc_device * isc)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 
xisc_parse_dt(struct device * dev,struct isc_device * isc)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;
320 	struct isc_subdev_entity *subdev_entity;
321 	unsigned int flags;
322 	int ret = -EINVAL;
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 	for_each_endpoint_of_node(np, epn) {
330 		struct v4l2_fwnode_endpoint v4l2_epn = { .bus_type = 0 };
331 
332 		ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(epn),
333 						 &v4l2_epn);
334 		if (ret) {
335 			ret = -EINVAL;
336 			dev_err(dev, "Could not parse the endpoint\n");
337 			break;
338 		}
339 
340 		subdev_entity = devm_kzalloc(dev, sizeof(*subdev_entity),
341 					     GFP_KERNEL);
342 		if (!subdev_entity) {
343 			ret = -ENOMEM;
344 			break;
345 		}
346 		subdev_entity->epn = epn;
347 
348 		flags = v4l2_epn.bus.parallel.flags;
349 
350 		if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
351 			subdev_entity->pfe_cfg0 = ISC_PFE_CFG0_HPOL_LOW;
352 
353 		if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
354 			subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_VPOL_LOW;
355 
356 		if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
357 			subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_PPOL_LOW;
358 
359 		if (v4l2_epn.bus_type == V4L2_MBUS_BT656)
360 			subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_CCIR_CRC |
361 					ISC_PFE_CFG0_CCIR656;
362 
363 		if (mipi_mode)
364 			subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_MIPI;
365 
366 		list_add_tail(&subdev_entity->list, &isc->subdev_entities);
367 	}
368 	of_node_put(epn);
369 
370 	return ret;
371 }
372 
microchip_xisc_probe(struct platform_device * pdev)373 static int microchip_xisc_probe(struct platform_device *pdev)
374 {
375 	struct device *dev = &pdev->dev;
376 	struct isc_device *isc;
377 	void __iomem *io_base;
378 	struct isc_subdev_entity *subdev_entity;
379 	int irq;
380 	int ret;
381 	u32 ver;
382 
383 	isc = devm_kzalloc(dev, sizeof(*isc), GFP_KERNEL);
384 	if (!isc)
385 		return -ENOMEM;
386 
387 	platform_set_drvdata(pdev, isc);
388 	isc->dev = dev;
389 
390 	io_base = devm_platform_ioremap_resource(pdev, 0);
391 	if (IS_ERR(io_base))
392 		return PTR_ERR(io_base);
393 
394 	isc->regmap = devm_regmap_init_mmio(dev, io_base, &atmel_isc_regmap_config);
395 	if (IS_ERR(isc->regmap)) {
396 		ret = PTR_ERR(isc->regmap);
397 		dev_err(dev, "failed to init register map: %d\n", ret);
398 		return ret;
399 	}
400 
401 	irq = platform_get_irq(pdev, 0);
402 	if (irq < 0)
403 		return irq;
404 
405 	ret = devm_request_irq(dev, irq, atmel_isc_interrupt, 0,
406 			       "microchip-sama7g5-xisc", isc);
407 	if (ret < 0) {
408 		dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
409 			irq, ret);
410 		return ret;
411 	}
412 
413 	isc->gamma_table = isc_sama7g5_gamma_table;
414 	isc->gamma_max = 0;
415 
416 	isc->max_width = ISC_SAMA7G5_MAX_SUPPORT_WIDTH;
417 	isc->max_height = ISC_SAMA7G5_MAX_SUPPORT_HEIGHT;
418 
419 	isc->config_dpc = isc_sama7g5_config_dpc;
420 	isc->config_csc = isc_sama7g5_config_csc;
421 	isc->config_cbc = isc_sama7g5_config_cbc;
422 	isc->config_cc = isc_sama7g5_config_cc;
423 	isc->config_gam = isc_sama7g5_config_gam;
424 	isc->config_rlp = isc_sama7g5_config_rlp;
425 	isc->config_ctrls = isc_sama7g5_config_ctrls;
426 
427 	isc->adapt_pipeline = isc_sama7g5_adapt_pipeline;
428 
429 	isc->offsets.csc = ISC_SAMA7G5_CSC_OFFSET;
430 	isc->offsets.cbc = ISC_SAMA7G5_CBC_OFFSET;
431 	isc->offsets.sub422 = ISC_SAMA7G5_SUB422_OFFSET;
432 	isc->offsets.sub420 = ISC_SAMA7G5_SUB420_OFFSET;
433 	isc->offsets.rlp = ISC_SAMA7G5_RLP_OFFSET;
434 	isc->offsets.his = ISC_SAMA7G5_HIS_OFFSET;
435 	isc->offsets.dma = ISC_SAMA7G5_DMA_OFFSET;
436 	isc->offsets.version = ISC_SAMA7G5_VERSION_OFFSET;
437 	isc->offsets.his_entry = ISC_SAMA7G5_HIS_ENTRY_OFFSET;
438 
439 	isc->controller_formats = sama7g5_controller_formats;
440 	isc->controller_formats_size = ARRAY_SIZE(sama7g5_controller_formats);
441 	isc->formats_list = sama7g5_formats_list;
442 	isc->formats_list_size = ARRAY_SIZE(sama7g5_formats_list);
443 
444 	/* sama7g5-isc RAM access port is full AXI4 - 32 bits per beat */
445 	isc->dcfg = ISC_DCFG_YMBSIZE_BEATS32 | ISC_DCFG_CMBSIZE_BEATS32;
446 
447 	/* sama7g5-isc : ISPCK does not exist, ISC is clocked by MCK */
448 	isc->ispck_required = false;
449 
450 	ret = atmel_isc_pipeline_init(isc);
451 	if (ret)
452 		return ret;
453 
454 	isc->hclock = devm_clk_get(dev, "hclock");
455 	if (IS_ERR(isc->hclock)) {
456 		ret = PTR_ERR(isc->hclock);
457 		dev_err(dev, "failed to get hclock: %d\n", ret);
458 		return ret;
459 	}
460 
461 	ret = clk_prepare_enable(isc->hclock);
462 	if (ret) {
463 		dev_err(dev, "failed to enable hclock: %d\n", ret);
464 		return ret;
465 	}
466 
467 	ret = atmel_isc_clk_init(isc);
468 	if (ret) {
469 		dev_err(dev, "failed to init isc clock: %d\n", ret);
470 		goto unprepare_hclk;
471 	}
472 
473 	ret = v4l2_device_register(dev, &isc->v4l2_dev);
474 	if (ret) {
475 		dev_err(dev, "unable to register v4l2 device.\n");
476 		goto unprepare_hclk;
477 	}
478 
479 	ret = xisc_parse_dt(dev, isc);
480 	if (ret) {
481 		dev_err(dev, "fail to parse device tree\n");
482 		goto unregister_v4l2_device;
483 	}
484 
485 	if (list_empty(&isc->subdev_entities)) {
486 		dev_err(dev, "no subdev found\n");
487 		ret = -ENODEV;
488 		goto unregister_v4l2_device;
489 	}
490 
491 	list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
492 		struct v4l2_async_connection *asd;
493 		struct fwnode_handle *fwnode =
494 			of_fwnode_handle(subdev_entity->epn);
495 
496 		v4l2_async_nf_init(&subdev_entity->notifier, &isc->v4l2_dev);
497 
498 		asd = v4l2_async_nf_add_fwnode_remote(&subdev_entity->notifier,
499 						      fwnode,
500 						      struct v4l2_async_connection);
501 
502 		of_node_put(subdev_entity->epn);
503 		subdev_entity->epn = NULL;
504 
505 		if (IS_ERR(asd)) {
506 			ret = PTR_ERR(asd);
507 			goto cleanup_subdev;
508 		}
509 
510 		subdev_entity->notifier.ops = &atmel_isc_async_ops;
511 
512 		ret = v4l2_async_nf_register(&subdev_entity->notifier);
513 		if (ret) {
514 			dev_err(dev, "fail to register async notifier\n");
515 			goto cleanup_subdev;
516 		}
517 
518 		if (video_is_registered(&isc->video_dev))
519 			break;
520 	}
521 
522 	pm_runtime_set_active(dev);
523 	pm_runtime_enable(dev);
524 	pm_request_idle(dev);
525 
526 	regmap_read(isc->regmap, ISC_VERSION + isc->offsets.version, &ver);
527 	dev_info(dev, "Microchip XISC version %x\n", ver);
528 
529 	return 0;
530 
531 cleanup_subdev:
532 	atmel_isc_subdev_cleanup(isc);
533 
534 unregister_v4l2_device:
535 	v4l2_device_unregister(&isc->v4l2_dev);
536 
537 unprepare_hclk:
538 	clk_disable_unprepare(isc->hclock);
539 
540 	atmel_isc_clk_cleanup(isc);
541 
542 	return ret;
543 }
544 
microchip_xisc_remove(struct platform_device * pdev)545 static void microchip_xisc_remove(struct platform_device *pdev)
546 {
547 	struct isc_device *isc = platform_get_drvdata(pdev);
548 
549 	pm_runtime_disable(&pdev->dev);
550 
551 	atmel_isc_subdev_cleanup(isc);
552 
553 	v4l2_device_unregister(&isc->v4l2_dev);
554 
555 	clk_disable_unprepare(isc->hclock);
556 
557 	atmel_isc_clk_cleanup(isc);
558 }
559 
xisc_runtime_suspend(struct device * dev)560 static int __maybe_unused xisc_runtime_suspend(struct device *dev)
561 {
562 	struct isc_device *isc = dev_get_drvdata(dev);
563 
564 	clk_disable_unprepare(isc->hclock);
565 
566 	return 0;
567 }
568 
xisc_runtime_resume(struct device * dev)569 static int __maybe_unused xisc_runtime_resume(struct device *dev)
570 {
571 	struct isc_device *isc = dev_get_drvdata(dev);
572 	int ret;
573 
574 	ret = clk_prepare_enable(isc->hclock);
575 	if (ret)
576 		return ret;
577 
578 	return ret;
579 }
580 
581 static const struct dev_pm_ops microchip_xisc_dev_pm_ops = {
582 	SET_RUNTIME_PM_OPS(xisc_runtime_suspend, xisc_runtime_resume, NULL)
583 };
584 
585 #if IS_ENABLED(CONFIG_OF)
586 static const struct of_device_id microchip_xisc_of_match[] = {
587 	{ .compatible = "microchip,sama7g5-isc" },
588 	{ }
589 };
590 MODULE_DEVICE_TABLE(of, microchip_xisc_of_match);
591 #endif
592 
593 static struct platform_driver microchip_xisc_driver = {
594 	.probe	= microchip_xisc_probe,
595 	.remove_new = microchip_xisc_remove,
596 	.driver	= {
597 		.name		= "microchip-sama7g5-xisc",
598 		.pm		= &microchip_xisc_dev_pm_ops,
599 		.of_match_table = of_match_ptr(microchip_xisc_of_match),
600 	},
601 };
602 
603 module_platform_driver(microchip_xisc_driver);
604 
605 MODULE_AUTHOR("Eugen Hristev <eugen.hristev@microchip.com>");
606 MODULE_DESCRIPTION("The V4L2 driver for Microchip-XISC");
607 MODULE_LICENSE("GPL v2");
608