]> Git Repo - linux.git/blob - drivers/media/platform/microchip/microchip-sama5d2-isc.c
arm64: avoid prototype warnings for syscalls
[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 = NULL;
357         struct isc_subdev_entity *subdev_entity;
358         unsigned int flags;
359         int ret;
360
361         INIT_LIST_HEAD(&isc->subdev_entities);
362
363         while (1) {
364                 struct v4l2_fwnode_endpoint v4l2_epn = { .bus_type = 0 };
365
366                 epn = of_graph_get_next_endpoint(np, epn);
367                 if (!epn)
368                         return 0;
369
370                 ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(epn),
371                                                  &v4l2_epn);
372                 if (ret) {
373                         ret = -EINVAL;
374                         dev_err(dev, "Could not parse the endpoint\n");
375                         break;
376                 }
377
378                 subdev_entity = devm_kzalloc(dev, sizeof(*subdev_entity),
379                                              GFP_KERNEL);
380                 if (!subdev_entity) {
381                         ret = -ENOMEM;
382                         break;
383                 }
384                 subdev_entity->epn = epn;
385
386                 flags = v4l2_epn.bus.parallel.flags;
387
388                 if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
389                         subdev_entity->pfe_cfg0 = ISC_PFE_CFG0_HPOL_LOW;
390
391                 if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
392                         subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_VPOL_LOW;
393
394                 if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
395                         subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_PPOL_LOW;
396
397                 if (v4l2_epn.bus_type == V4L2_MBUS_BT656)
398                         subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_CCIR_CRC |
399                                         ISC_PFE_CFG0_CCIR656;
400
401                 list_add_tail(&subdev_entity->list, &isc->subdev_entities);
402         }
403         of_node_put(epn);
404
405         return ret;
406 }
407
408 static int microchip_isc_probe(struct platform_device *pdev)
409 {
410         struct device *dev = &pdev->dev;
411         struct isc_device *isc;
412         struct resource *res;
413         void __iomem *io_base;
414         struct isc_subdev_entity *subdev_entity;
415         int irq;
416         int ret;
417         u32 ver;
418
419         isc = devm_kzalloc(dev, sizeof(*isc), GFP_KERNEL);
420         if (!isc)
421                 return -ENOMEM;
422
423         platform_set_drvdata(pdev, isc);
424         isc->dev = dev;
425
426         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
427         io_base = devm_ioremap_resource(dev, res);
428         if (IS_ERR(io_base))
429                 return PTR_ERR(io_base);
430
431         isc->regmap = devm_regmap_init_mmio(dev, io_base, &microchip_isc_regmap_config);
432         if (IS_ERR(isc->regmap)) {
433                 ret = PTR_ERR(isc->regmap);
434                 dev_err(dev, "failed to init register map: %d\n", ret);
435                 return ret;
436         }
437
438         irq = platform_get_irq(pdev, 0);
439         if (irq < 0)
440                 return irq;
441
442         ret = devm_request_irq(dev, irq, microchip_isc_interrupt, 0,
443                                "microchip-sama5d2-isc", isc);
444         if (ret < 0) {
445                 dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
446                         irq, ret);
447                 return ret;
448         }
449
450         isc->gamma_table = isc_sama5d2_gamma_table;
451         isc->gamma_max = 2;
452
453         isc->max_width = ISC_SAMA5D2_MAX_SUPPORT_WIDTH;
454         isc->max_height = ISC_SAMA5D2_MAX_SUPPORT_HEIGHT;
455
456         isc->config_dpc = isc_sama5d2_config_dpc;
457         isc->config_csc = isc_sama5d2_config_csc;
458         isc->config_cbc = isc_sama5d2_config_cbc;
459         isc->config_cc = isc_sama5d2_config_cc;
460         isc->config_gam = isc_sama5d2_config_gam;
461         isc->config_rlp = isc_sama5d2_config_rlp;
462         isc->config_ctrls = isc_sama5d2_config_ctrls;
463
464         isc->adapt_pipeline = isc_sama5d2_adapt_pipeline;
465
466         isc->offsets.csc = ISC_SAMA5D2_CSC_OFFSET;
467         isc->offsets.cbc = ISC_SAMA5D2_CBC_OFFSET;
468         isc->offsets.sub422 = ISC_SAMA5D2_SUB422_OFFSET;
469         isc->offsets.sub420 = ISC_SAMA5D2_SUB420_OFFSET;
470         isc->offsets.rlp = ISC_SAMA5D2_RLP_OFFSET;
471         isc->offsets.his = ISC_SAMA5D2_HIS_OFFSET;
472         isc->offsets.dma = ISC_SAMA5D2_DMA_OFFSET;
473         isc->offsets.version = ISC_SAMA5D2_VERSION_OFFSET;
474         isc->offsets.his_entry = ISC_SAMA5D2_HIS_ENTRY_OFFSET;
475
476         isc->controller_formats = sama5d2_controller_formats;
477         isc->controller_formats_size = ARRAY_SIZE(sama5d2_controller_formats);
478         isc->formats_list = sama5d2_formats_list;
479         isc->formats_list_size = ARRAY_SIZE(sama5d2_formats_list);
480
481         /* sama5d2-isc - 8 bits per beat */
482         isc->dcfg = ISC_DCFG_YMBSIZE_BEATS8 | ISC_DCFG_CMBSIZE_BEATS8;
483
484         /* sama5d2-isc : ISPCK is required and mandatory */
485         isc->ispck_required = true;
486
487         ret = microchip_isc_pipeline_init(isc);
488         if (ret)
489                 return ret;
490
491         isc->hclock = devm_clk_get(dev, "hclock");
492         if (IS_ERR(isc->hclock)) {
493                 ret = PTR_ERR(isc->hclock);
494                 dev_err(dev, "failed to get hclock: %d\n", ret);
495                 return ret;
496         }
497
498         ret = clk_prepare_enable(isc->hclock);
499         if (ret) {
500                 dev_err(dev, "failed to enable hclock: %d\n", ret);
501                 return ret;
502         }
503
504         ret = microchip_isc_clk_init(isc);
505         if (ret) {
506                 dev_err(dev, "failed to init isc clock: %d\n", ret);
507                 goto unprepare_hclk;
508         }
509         ret = v4l2_device_register(dev, &isc->v4l2_dev);
510         if (ret) {
511                 dev_err(dev, "unable to register v4l2 device.\n");
512                 goto unprepare_clk;
513         }
514
515         ret = isc_parse_dt(dev, isc);
516         if (ret) {
517                 dev_err(dev, "fail to parse device tree\n");
518                 goto unregister_v4l2_device;
519         }
520
521         if (list_empty(&isc->subdev_entities)) {
522                 dev_err(dev, "no subdev found\n");
523                 ret = -ENODEV;
524                 goto unregister_v4l2_device;
525         }
526
527         list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
528                 struct v4l2_async_subdev *asd;
529                 struct fwnode_handle *fwnode =
530                         of_fwnode_handle(subdev_entity->epn);
531
532                 v4l2_async_nf_init(&subdev_entity->notifier);
533
534                 asd = v4l2_async_nf_add_fwnode_remote(&subdev_entity->notifier,
535                                                       fwnode,
536                                                       struct v4l2_async_subdev);
537
538                 of_node_put(subdev_entity->epn);
539                 subdev_entity->epn = NULL;
540
541                 if (IS_ERR(asd)) {
542                         ret = PTR_ERR(asd);
543                         goto cleanup_subdev;
544                 }
545
546                 subdev_entity->notifier.ops = &microchip_isc_async_ops;
547
548                 ret = v4l2_async_nf_register(&isc->v4l2_dev,
549                                              &subdev_entity->notifier);
550                 if (ret) {
551                         dev_err(dev, "fail to register async notifier\n");
552                         goto cleanup_subdev;
553                 }
554
555                 if (video_is_registered(&isc->video_dev))
556                         break;
557         }
558
559         regmap_read(isc->regmap, ISC_VERSION + isc->offsets.version, &ver);
560
561         ret = isc_mc_init(isc, ver);
562         if (ret < 0)
563                 goto isc_probe_mc_init_err;
564
565         pm_runtime_set_active(dev);
566         pm_runtime_enable(dev);
567         pm_request_idle(dev);
568
569         isc->ispck = isc->isc_clks[ISC_ISPCK].clk;
570
571         ret = clk_prepare_enable(isc->ispck);
572         if (ret) {
573                 dev_err(dev, "failed to enable ispck: %d\n", ret);
574                 goto disable_pm;
575         }
576
577         /* ispck should be greater or equal to hclock */
578         ret = clk_set_rate(isc->ispck, clk_get_rate(isc->hclock));
579         if (ret) {
580                 dev_err(dev, "failed to set ispck rate: %d\n", ret);
581                 goto unprepare_clk;
582         }
583
584         dev_info(dev, "Microchip ISC version %x\n", ver);
585
586         return 0;
587
588 unprepare_clk:
589         clk_disable_unprepare(isc->ispck);
590
591 disable_pm:
592         pm_runtime_disable(dev);
593
594 isc_probe_mc_init_err:
595         isc_mc_cleanup(isc);
596
597 cleanup_subdev:
598         microchip_isc_subdev_cleanup(isc);
599
600 unregister_v4l2_device:
601         v4l2_device_unregister(&isc->v4l2_dev);
602
603 unprepare_hclk:
604         clk_disable_unprepare(isc->hclock);
605
606         microchip_isc_clk_cleanup(isc);
607
608         return ret;
609 }
610
611 static void microchip_isc_remove(struct platform_device *pdev)
612 {
613         struct isc_device *isc = platform_get_drvdata(pdev);
614
615         pm_runtime_disable(&pdev->dev);
616
617         isc_mc_cleanup(isc);
618
619         microchip_isc_subdev_cleanup(isc);
620
621         v4l2_device_unregister(&isc->v4l2_dev);
622
623         clk_disable_unprepare(isc->ispck);
624         clk_disable_unprepare(isc->hclock);
625
626         microchip_isc_clk_cleanup(isc);
627 }
628
629 static int __maybe_unused isc_runtime_suspend(struct device *dev)
630 {
631         struct isc_device *isc = dev_get_drvdata(dev);
632
633         clk_disable_unprepare(isc->ispck);
634         clk_disable_unprepare(isc->hclock);
635
636         return 0;
637 }
638
639 static int __maybe_unused isc_runtime_resume(struct device *dev)
640 {
641         struct isc_device *isc = dev_get_drvdata(dev);
642         int ret;
643
644         ret = clk_prepare_enable(isc->hclock);
645         if (ret)
646                 return ret;
647
648         ret = clk_prepare_enable(isc->ispck);
649         if (ret)
650                 clk_disable_unprepare(isc->hclock);
651
652         return ret;
653 }
654
655 static const struct dev_pm_ops microchip_isc_dev_pm_ops = {
656         SET_RUNTIME_PM_OPS(isc_runtime_suspend, isc_runtime_resume, NULL)
657 };
658
659 #if IS_ENABLED(CONFIG_OF)
660 static const struct of_device_id microchip_isc_of_match[] = {
661         { .compatible = "atmel,sama5d2-isc" },
662         { }
663 };
664 MODULE_DEVICE_TABLE(of, microchip_isc_of_match);
665 #endif
666
667 static struct platform_driver microchip_isc_driver = {
668         .probe  = microchip_isc_probe,
669         .remove_new = microchip_isc_remove,
670         .driver = {
671                 .name           = "microchip-sama5d2-isc",
672                 .pm             = &microchip_isc_dev_pm_ops,
673                 .of_match_table = of_match_ptr(microchip_isc_of_match),
674         },
675 };
676
677 module_platform_driver(microchip_isc_driver);
678
679 MODULE_AUTHOR("Songjun Wu");
680 MODULE_DESCRIPTION("The V4L2 driver for Microchip-ISC");
681 MODULE_LICENSE("GPL v2");
This page took 0.081956 seconds and 4 git commands to generate.