GNU Linux-libre 5.19-rc6-gnu
[releases.git] / drivers / media / platform / atmel / atmel-sama5d2-isc.c
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, &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, 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 = 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 = 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 = &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         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         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         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         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");