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