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