GNU Linux-libre 5.19-rc6-gnu
[releases.git] / drivers / media / platform / atmel / atmel-sama7g5-isc.c
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         struct resource *res;
382         void __iomem *io_base;
383         struct isc_subdev_entity *subdev_entity;
384         int irq;
385         int ret;
386         u32 ver;
387
388         isc = devm_kzalloc(dev, sizeof(*isc), GFP_KERNEL);
389         if (!isc)
390                 return -ENOMEM;
391
392         platform_set_drvdata(pdev, isc);
393         isc->dev = dev;
394
395         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
396         io_base = devm_ioremap_resource(dev, res);
397         if (IS_ERR(io_base))
398                 return PTR_ERR(io_base);
399
400         isc->regmap = devm_regmap_init_mmio(dev, io_base, &isc_regmap_config);
401         if (IS_ERR(isc->regmap)) {
402                 ret = PTR_ERR(isc->regmap);
403                 dev_err(dev, "failed to init register map: %d\n", ret);
404                 return ret;
405         }
406
407         irq = platform_get_irq(pdev, 0);
408         if (irq < 0)
409                 return irq;
410
411         ret = devm_request_irq(dev, irq, isc_interrupt, 0,
412                                "microchip-sama7g5-xisc", isc);
413         if (ret < 0) {
414                 dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
415                         irq, ret);
416                 return ret;
417         }
418
419         isc->gamma_table = isc_sama7g5_gamma_table;
420         isc->gamma_max = 0;
421
422         isc->max_width = ISC_SAMA7G5_MAX_SUPPORT_WIDTH;
423         isc->max_height = ISC_SAMA7G5_MAX_SUPPORT_HEIGHT;
424
425         isc->config_dpc = isc_sama7g5_config_dpc;
426         isc->config_csc = isc_sama7g5_config_csc;
427         isc->config_cbc = isc_sama7g5_config_cbc;
428         isc->config_cc = isc_sama7g5_config_cc;
429         isc->config_gam = isc_sama7g5_config_gam;
430         isc->config_rlp = isc_sama7g5_config_rlp;
431         isc->config_ctrls = isc_sama7g5_config_ctrls;
432
433         isc->adapt_pipeline = isc_sama7g5_adapt_pipeline;
434
435         isc->offsets.csc = ISC_SAMA7G5_CSC_OFFSET;
436         isc->offsets.cbc = ISC_SAMA7G5_CBC_OFFSET;
437         isc->offsets.sub422 = ISC_SAMA7G5_SUB422_OFFSET;
438         isc->offsets.sub420 = ISC_SAMA7G5_SUB420_OFFSET;
439         isc->offsets.rlp = ISC_SAMA7G5_RLP_OFFSET;
440         isc->offsets.his = ISC_SAMA7G5_HIS_OFFSET;
441         isc->offsets.dma = ISC_SAMA7G5_DMA_OFFSET;
442         isc->offsets.version = ISC_SAMA7G5_VERSION_OFFSET;
443         isc->offsets.his_entry = ISC_SAMA7G5_HIS_ENTRY_OFFSET;
444
445         isc->controller_formats = sama7g5_controller_formats;
446         isc->controller_formats_size = ARRAY_SIZE(sama7g5_controller_formats);
447         isc->formats_list = sama7g5_formats_list;
448         isc->formats_list_size = ARRAY_SIZE(sama7g5_formats_list);
449
450         /* sama7g5-isc RAM access port is full AXI4 - 32 bits per beat */
451         isc->dcfg = ISC_DCFG_YMBSIZE_BEATS32 | ISC_DCFG_CMBSIZE_BEATS32;
452
453         /* sama7g5-isc : ISPCK does not exist, ISC is clocked by MCK */
454         isc->ispck_required = false;
455
456         ret = isc_pipeline_init(isc);
457         if (ret)
458                 return ret;
459
460         isc->hclock = devm_clk_get(dev, "hclock");
461         if (IS_ERR(isc->hclock)) {
462                 ret = PTR_ERR(isc->hclock);
463                 dev_err(dev, "failed to get hclock: %d\n", ret);
464                 return ret;
465         }
466
467         ret = clk_prepare_enable(isc->hclock);
468         if (ret) {
469                 dev_err(dev, "failed to enable hclock: %d\n", ret);
470                 return ret;
471         }
472
473         ret = isc_clk_init(isc);
474         if (ret) {
475                 dev_err(dev, "failed to init isc clock: %d\n", ret);
476                 goto unprepare_hclk;
477         }
478
479         ret = v4l2_device_register(dev, &isc->v4l2_dev);
480         if (ret) {
481                 dev_err(dev, "unable to register v4l2 device.\n");
482                 goto unprepare_hclk;
483         }
484
485         ret = xisc_parse_dt(dev, isc);
486         if (ret) {
487                 dev_err(dev, "fail to parse device tree\n");
488                 goto unregister_v4l2_device;
489         }
490
491         if (list_empty(&isc->subdev_entities)) {
492                 dev_err(dev, "no subdev found\n");
493                 ret = -ENODEV;
494                 goto unregister_v4l2_device;
495         }
496
497         list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
498                 struct v4l2_async_subdev *asd;
499                 struct fwnode_handle *fwnode =
500                         of_fwnode_handle(subdev_entity->epn);
501
502                 v4l2_async_nf_init(&subdev_entity->notifier);
503
504                 asd = v4l2_async_nf_add_fwnode_remote(&subdev_entity->notifier,
505                                                       fwnode,
506                                                       struct v4l2_async_subdev);
507
508                 of_node_put(subdev_entity->epn);
509                 subdev_entity->epn = NULL;
510
511                 if (IS_ERR(asd)) {
512                         ret = PTR_ERR(asd);
513                         goto cleanup_subdev;
514                 }
515
516                 subdev_entity->notifier.ops = &isc_async_ops;
517
518                 ret = v4l2_async_nf_register(&isc->v4l2_dev,
519                                              &subdev_entity->notifier);
520                 if (ret) {
521                         dev_err(dev, "fail to register async notifier\n");
522                         goto cleanup_subdev;
523                 }
524
525                 if (video_is_registered(&isc->video_dev))
526                         break;
527         }
528
529         pm_runtime_set_active(dev);
530         pm_runtime_enable(dev);
531         pm_request_idle(dev);
532
533         regmap_read(isc->regmap, ISC_VERSION + isc->offsets.version, &ver);
534         dev_info(dev, "Microchip XISC version %x\n", ver);
535
536         return 0;
537
538 cleanup_subdev:
539         isc_subdev_cleanup(isc);
540
541 unregister_v4l2_device:
542         v4l2_device_unregister(&isc->v4l2_dev);
543
544 unprepare_hclk:
545         clk_disable_unprepare(isc->hclock);
546
547         isc_clk_cleanup(isc);
548
549         return ret;
550 }
551
552 static int microchip_xisc_remove(struct platform_device *pdev)
553 {
554         struct isc_device *isc = platform_get_drvdata(pdev);
555
556         pm_runtime_disable(&pdev->dev);
557
558         isc_subdev_cleanup(isc);
559
560         v4l2_device_unregister(&isc->v4l2_dev);
561
562         clk_disable_unprepare(isc->hclock);
563
564         isc_clk_cleanup(isc);
565
566         return 0;
567 }
568
569 static int __maybe_unused xisc_runtime_suspend(struct device *dev)
570 {
571         struct isc_device *isc = dev_get_drvdata(dev);
572
573         clk_disable_unprepare(isc->hclock);
574
575         return 0;
576 }
577
578 static int __maybe_unused xisc_runtime_resume(struct device *dev)
579 {
580         struct isc_device *isc = dev_get_drvdata(dev);
581         int ret;
582
583         ret = clk_prepare_enable(isc->hclock);
584         if (ret)
585                 return ret;
586
587         return ret;
588 }
589
590 static const struct dev_pm_ops microchip_xisc_dev_pm_ops = {
591         SET_RUNTIME_PM_OPS(xisc_runtime_suspend, xisc_runtime_resume, NULL)
592 };
593
594 static const struct of_device_id microchip_xisc_of_match[] = {
595         { .compatible = "microchip,sama7g5-isc" },
596         { }
597 };
598 MODULE_DEVICE_TABLE(of, microchip_xisc_of_match);
599
600 static struct platform_driver microchip_xisc_driver = {
601         .probe  = microchip_xisc_probe,
602         .remove = microchip_xisc_remove,
603         .driver = {
604                 .name           = "microchip-sama7g5-xisc",
605                 .pm             = &microchip_xisc_dev_pm_ops,
606                 .of_match_table = of_match_ptr(microchip_xisc_of_match),
607         },
608 };
609
610 module_platform_driver(microchip_xisc_driver);
611
612 MODULE_AUTHOR("Eugen Hristev <eugen.hristev@microchip.com>");
613 MODULE_DESCRIPTION("The V4L2 driver for Microchip-XISC");
614 MODULE_LICENSE("GPL v2");