]> Git Repo - linux.git/blob - drivers/media/platform/microchip/microchip-sama7g5-isc.c
arm64: avoid prototype warnings for syscalls
[linux.git] / drivers / media / platform / microchip / microchip-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 <[email protected]>
8  *
9  * Sensor-->PFE-->DPC-->WB-->CFA-->CC-->GAM-->VHXS-->CSC-->CBHS-->SUB-->RLP-->DMA-->HIS
10  *
11  * ISC video pipeline integrates the following submodules:
12  * PFE: Parallel Front End to sample the camera sensor input stream
13  * DPC: Defective Pixel Correction with black offset correction, green disparity
14  *      correction and defective pixel correction (3 modules total)
15  *  WB: Programmable white balance in the Bayer domain
16  * CFA: Color filter array interpolation module
17  *  CC: Programmable color correction
18  * GAM: Gamma correction
19  *VHXS: Vertical and Horizontal Scaler
20  * CSC: Programmable color space conversion
21  *CBHS: Contrast Brightness Hue and Saturation control
22  * SUB: This module performs YCbCr444 to YCbCr420 chrominance subsampling
23  * RLP: This module performs rounding, range limiting
24  *      and packing of the incoming data
25  * DMA: This module performs DMA master accesses to write frames to external RAM
26  * HIS: Histogram module performs statistic counters on the frames
27  */
28
29 #include <linux/clk.h>
30 #include <linux/clkdev.h>
31 #include <linux/clk-provider.h>
32 #include <linux/delay.h>
33 #include <linux/interrupt.h>
34 #include <linux/math64.h>
35 #include <linux/module.h>
36 #include <linux/of.h>
37 #include <linux/of_graph.h>
38 #include <linux/platform_device.h>
39 #include <linux/pm_runtime.h>
40 #include <linux/regmap.h>
41 #include <linux/videodev2.h>
42
43 #include <media/v4l2-ctrls.h>
44 #include <media/v4l2-device.h>
45 #include <media/v4l2-event.h>
46 #include <media/v4l2-image-sizes.h>
47 #include <media/v4l2-ioctl.h>
48 #include <media/v4l2-fwnode.h>
49 #include <media/v4l2-subdev.h>
50 #include <media/videobuf2-dma-contig.h>
51
52 #include "microchip-isc-regs.h"
53 #include "microchip-isc.h"
54
55 #define ISC_SAMA7G5_MAX_SUPPORT_WIDTH   3264
56 #define ISC_SAMA7G5_MAX_SUPPORT_HEIGHT  2464
57
58 #define ISC_SAMA7G5_PIPELINE \
59         (WB_ENABLE | CFA_ENABLE | CC_ENABLE | GAM_ENABLES | CSC_ENABLE | \
60         CBC_ENABLE | SUB422_ENABLE | SUB420_ENABLE)
61
62 /* This is a list of the formats that the ISC can *output* */
63 static const struct isc_format sama7g5_controller_formats[] = {
64         {
65                 .fourcc         = V4L2_PIX_FMT_ARGB444,
66         }, {
67                 .fourcc         = V4L2_PIX_FMT_ARGB555,
68         }, {
69                 .fourcc         = V4L2_PIX_FMT_RGB565,
70         }, {
71                 .fourcc         = V4L2_PIX_FMT_ABGR32,
72         }, {
73                 .fourcc         = V4L2_PIX_FMT_XBGR32,
74         }, {
75                 .fourcc         = V4L2_PIX_FMT_YUV420,
76         }, {
77                 .fourcc         = V4L2_PIX_FMT_UYVY,
78         }, {
79                 .fourcc         = V4L2_PIX_FMT_VYUY,
80         }, {
81                 .fourcc         = V4L2_PIX_FMT_YUYV,
82         }, {
83                 .fourcc         = V4L2_PIX_FMT_YUV422P,
84         }, {
85                 .fourcc         = V4L2_PIX_FMT_GREY,
86         }, {
87                 .fourcc         = V4L2_PIX_FMT_Y10,
88         }, {
89                 .fourcc         = V4L2_PIX_FMT_Y16,
90         }, {
91                 .fourcc         = V4L2_PIX_FMT_SBGGR8,
92                 .raw            = true,
93         }, {
94                 .fourcc         = V4L2_PIX_FMT_SGBRG8,
95                 .raw            = true,
96         }, {
97                 .fourcc         = V4L2_PIX_FMT_SGRBG8,
98                 .raw            = true,
99         }, {
100                 .fourcc         = V4L2_PIX_FMT_SRGGB8,
101                 .raw            = true,
102         }, {
103                 .fourcc         = V4L2_PIX_FMT_SBGGR10,
104                 .raw            = true,
105         }, {
106                 .fourcc         = V4L2_PIX_FMT_SGBRG10,
107                 .raw            = true,
108         }, {
109                 .fourcc         = V4L2_PIX_FMT_SGRBG10,
110                 .raw            = true,
111         }, {
112                 .fourcc         = V4L2_PIX_FMT_SRGGB10,
113                 .raw            = true,
114         }, {
115                 .fourcc         = V4L2_PIX_FMT_SBGGR12,
116                 .raw            = true,
117         }, {
118                 .fourcc         = V4L2_PIX_FMT_SGBRG12,
119                 .raw            = true,
120         }, {
121                 .fourcc         = V4L2_PIX_FMT_SGRBG12,
122                 .raw            = true,
123         }, {
124                 .fourcc         = V4L2_PIX_FMT_SRGGB12,
125                 .raw            = true,
126         },
127 };
128
129 /* This is a list of formats that the ISC can receive as *input* */
130 static struct isc_format sama7g5_formats_list[] = {
131         {
132                 .fourcc         = V4L2_PIX_FMT_SBGGR8,
133                 .mbus_code      = MEDIA_BUS_FMT_SBGGR8_1X8,
134                 .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
135                 .cfa_baycfg     = ISC_BAY_CFG_BGBG,
136         },
137         {
138                 .fourcc         = V4L2_PIX_FMT_SGBRG8,
139                 .mbus_code      = MEDIA_BUS_FMT_SGBRG8_1X8,
140                 .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
141                 .cfa_baycfg     = ISC_BAY_CFG_GBGB,
142         },
143         {
144                 .fourcc         = V4L2_PIX_FMT_SGRBG8,
145                 .mbus_code      = MEDIA_BUS_FMT_SGRBG8_1X8,
146                 .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
147                 .cfa_baycfg     = ISC_BAY_CFG_GRGR,
148         },
149         {
150                 .fourcc         = V4L2_PIX_FMT_SRGGB8,
151                 .mbus_code      = MEDIA_BUS_FMT_SRGGB8_1X8,
152                 .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
153                 .cfa_baycfg     = ISC_BAY_CFG_RGRG,
154         },
155         {
156                 .fourcc         = V4L2_PIX_FMT_SBGGR10,
157                 .mbus_code      = MEDIA_BUS_FMT_SBGGR10_1X10,
158                 .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TEN,
159                 .cfa_baycfg     = ISC_BAY_CFG_RGRG,
160         },
161         {
162                 .fourcc         = V4L2_PIX_FMT_SGBRG10,
163                 .mbus_code      = MEDIA_BUS_FMT_SGBRG10_1X10,
164                 .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TEN,
165                 .cfa_baycfg     = ISC_BAY_CFG_GBGB,
166         },
167         {
168                 .fourcc         = V4L2_PIX_FMT_SGRBG10,
169                 .mbus_code      = MEDIA_BUS_FMT_SGRBG10_1X10,
170                 .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TEN,
171                 .cfa_baycfg     = ISC_BAY_CFG_GRGR,
172         },
173         {
174                 .fourcc         = V4L2_PIX_FMT_SRGGB10,
175                 .mbus_code      = MEDIA_BUS_FMT_SRGGB10_1X10,
176                 .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TEN,
177                 .cfa_baycfg     = ISC_BAY_CFG_RGRG,
178         },
179         {
180                 .fourcc         = V4L2_PIX_FMT_SBGGR12,
181                 .mbus_code      = MEDIA_BUS_FMT_SBGGR12_1X12,
182                 .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TWELVE,
183                 .cfa_baycfg     = ISC_BAY_CFG_BGBG,
184         },
185         {
186                 .fourcc         = V4L2_PIX_FMT_SGBRG12,
187                 .mbus_code      = MEDIA_BUS_FMT_SGBRG12_1X12,
188                 .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TWELVE,
189                 .cfa_baycfg     = ISC_BAY_CFG_GBGB,
190         },
191         {
192                 .fourcc         = V4L2_PIX_FMT_SGRBG12,
193                 .mbus_code      = MEDIA_BUS_FMT_SGRBG12_1X12,
194                 .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TWELVE,
195                 .cfa_baycfg     = ISC_BAY_CFG_GRGR,
196         },
197         {
198                 .fourcc         = V4L2_PIX_FMT_SRGGB12,
199                 .mbus_code      = MEDIA_BUS_FMT_SRGGB12_1X12,
200                 .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TWELVE,
201                 .cfa_baycfg     = ISC_BAY_CFG_RGRG,
202         },
203         {
204                 .fourcc         = V4L2_PIX_FMT_GREY,
205                 .mbus_code      = MEDIA_BUS_FMT_Y8_1X8,
206                 .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
207         },
208         {
209                 .fourcc         = V4L2_PIX_FMT_YUYV,
210                 .mbus_code      = MEDIA_BUS_FMT_YUYV8_2X8,
211                 .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
212         },
213         {
214                 .fourcc         = V4L2_PIX_FMT_UYVY,
215                 .mbus_code      = MEDIA_BUS_FMT_UYVY8_2X8,
216                 .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
217         },
218         {
219                 .fourcc         = V4L2_PIX_FMT_RGB565,
220                 .mbus_code      = MEDIA_BUS_FMT_RGB565_2X8_LE,
221                 .pfe_cfg0_bps   = ISC_PFE_CFG0_BPS_EIGHT,
222         },
223         {
224                 .fourcc         = V4L2_PIX_FMT_Y10,
225                 .mbus_code      = MEDIA_BUS_FMT_Y10_1X10,
226                 .pfe_cfg0_bps   = ISC_PFG_CFG0_BPS_TEN,
227         },
228 };
229
230 static void isc_sama7g5_config_csc(struct isc_device *isc)
231 {
232         struct regmap *regmap = isc->regmap;
233
234         /* Convert RGB to YUV */
235         regmap_write(regmap, ISC_CSC_YR_YG + isc->offsets.csc,
236                      0x42 | (0x81 << 16));
237         regmap_write(regmap, ISC_CSC_YB_OY + isc->offsets.csc,
238                      0x19 | (0x10 << 16));
239         regmap_write(regmap, ISC_CSC_CBR_CBG + isc->offsets.csc,
240                      0xFDA | (0xFB6 << 16));
241         regmap_write(regmap, ISC_CSC_CBB_OCB + isc->offsets.csc,
242                      0x70 | (0x80 << 16));
243         regmap_write(regmap, ISC_CSC_CRR_CRG + isc->offsets.csc,
244                      0x70 | (0xFA2 << 16));
245         regmap_write(regmap, ISC_CSC_CRB_OCR + isc->offsets.csc,
246                      0xFEE | (0x80 << 16));
247 }
248
249 static void isc_sama7g5_config_cbc(struct isc_device *isc)
250 {
251         struct regmap *regmap = isc->regmap;
252
253         /* Configure what is set via v4l2 ctrls */
254         regmap_write(regmap, ISC_CBC_BRIGHT + isc->offsets.cbc, isc->ctrls.brightness);
255         regmap_write(regmap, ISC_CBC_CONTRAST + isc->offsets.cbc, isc->ctrls.contrast);
256         /* Configure Hue and Saturation as neutral midpoint */
257         regmap_write(regmap, ISC_CBCHS_HUE, 0);
258         regmap_write(regmap, ISC_CBCHS_SAT, (1 << 4));
259 }
260
261 static void isc_sama7g5_config_cc(struct isc_device *isc)
262 {
263         struct regmap *regmap = isc->regmap;
264
265         /* Configure each register at the neutral fixed point 1.0 or 0.0 */
266         regmap_write(regmap, ISC_CC_RR_RG, (1 << 8));
267         regmap_write(regmap, ISC_CC_RB_OR, 0);
268         regmap_write(regmap, ISC_CC_GR_GG, (1 << 8) << 16);
269         regmap_write(regmap, ISC_CC_GB_OG, 0);
270         regmap_write(regmap, ISC_CC_BR_BG, 0);
271         regmap_write(regmap, ISC_CC_BB_OB, (1 << 8));
272 }
273
274 static void isc_sama7g5_config_ctrls(struct isc_device *isc,
275                                      const struct v4l2_ctrl_ops *ops)
276 {
277         struct isc_ctrls *ctrls = &isc->ctrls;
278         struct v4l2_ctrl_handler *hdl = &ctrls->handler;
279
280         ctrls->contrast = 16;
281
282         v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -2048, 2047, 1, 16);
283 }
284
285 static void isc_sama7g5_config_dpc(struct isc_device *isc)
286 {
287         u32 bay_cfg = isc->config.sd_format->cfa_baycfg;
288         struct regmap *regmap = isc->regmap;
289
290         regmap_update_bits(regmap, ISC_DPC_CFG, ISC_DPC_CFG_BLOFF_MASK,
291                            (64 << ISC_DPC_CFG_BLOFF_SHIFT));
292         regmap_update_bits(regmap, ISC_DPC_CFG, ISC_DPC_CFG_BAYCFG_MASK,
293                            (bay_cfg << ISC_DPC_CFG_BAYCFG_SHIFT));
294 }
295
296 static void isc_sama7g5_config_gam(struct isc_device *isc)
297 {
298         struct regmap *regmap = isc->regmap;
299
300         regmap_update_bits(regmap, ISC_GAM_CTRL, ISC_GAM_CTRL_BIPART,
301                            ISC_GAM_CTRL_BIPART);
302 }
303
304 static void isc_sama7g5_config_rlp(struct isc_device *isc)
305 {
306         struct regmap *regmap = isc->regmap;
307         u32 rlp_mode = isc->config.rlp_cfg_mode;
308
309         regmap_update_bits(regmap, ISC_RLP_CFG + isc->offsets.rlp,
310                            ISC_RLP_CFG_MODE_MASK | ISC_RLP_CFG_LSH |
311                            ISC_RLP_CFG_YMODE_MASK, rlp_mode);
312 }
313
314 static void isc_sama7g5_adapt_pipeline(struct isc_device *isc)
315 {
316         isc->try_config.bits_pipeline &= ISC_SAMA7G5_PIPELINE;
317 }
318
319 /* Gamma table with gamma 1/2.2 */
320 static const u32 isc_sama7g5_gamma_table[][GAMMA_ENTRIES] = {
321         /* index 0 --> gamma bipartite */
322         {
323               0x980,  0x4c0320,  0x650260,  0x7801e0,  0x8701a0,  0x940180,
324            0xa00160,  0xab0120,  0xb40120,  0xbd0120,  0xc60100,  0xce0100,
325            0xd600e0,  0xdd00e0,  0xe400e0,  0xeb00c0,  0xf100c0,  0xf700c0,
326            0xfd00c0, 0x10300a0, 0x10800c0, 0x10e00a0, 0x11300a0, 0x11800a0,
327           0x11d00a0, 0x12200a0, 0x12700a0, 0x12c0080, 0x13000a0, 0x1350080,
328           0x13900a0, 0x13e0080, 0x1420076, 0x17d0062, 0x1ae0054, 0x1d8004a,
329           0x1fd0044, 0x21f003e, 0x23e003a, 0x25b0036, 0x2760032, 0x28f0030,
330           0x2a7002e, 0x2be002c, 0x2d4002c, 0x2ea0028, 0x2fe0028, 0x3120026,
331           0x3250024, 0x3370024, 0x3490022, 0x35a0022, 0x36b0020, 0x37b0020,
332           0x38b0020, 0x39b001e, 0x3aa001e, 0x3b9001c, 0x3c7001c, 0x3d5001c,
333           0x3e3001c, 0x3f1001c, 0x3ff001a, 0x40c001a },
334 };
335
336 static int xisc_parse_dt(struct device *dev, struct isc_device *isc)
337 {
338         struct device_node *np = dev->of_node;
339         struct device_node *epn = NULL;
340         struct isc_subdev_entity *subdev_entity;
341         unsigned int flags;
342         int ret;
343         bool mipi_mode;
344
345         INIT_LIST_HEAD(&isc->subdev_entities);
346
347         mipi_mode = of_property_read_bool(np, "microchip,mipi-mode");
348
349         while (1) {
350                 struct v4l2_fwnode_endpoint v4l2_epn = { .bus_type = 0 };
351
352                 epn = of_graph_get_next_endpoint(np, epn);
353                 if (!epn)
354                         return 0;
355
356                 ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(epn),
357                                                  &v4l2_epn);
358                 if (ret) {
359                         ret = -EINVAL;
360                         dev_err(dev, "Could not parse the endpoint\n");
361                         break;
362                 }
363
364                 subdev_entity = devm_kzalloc(dev, sizeof(*subdev_entity),
365                                              GFP_KERNEL);
366                 if (!subdev_entity) {
367                         ret = -ENOMEM;
368                         break;
369                 }
370                 subdev_entity->epn = epn;
371
372                 flags = v4l2_epn.bus.parallel.flags;
373
374                 if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
375                         subdev_entity->pfe_cfg0 = ISC_PFE_CFG0_HPOL_LOW;
376
377                 if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
378                         subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_VPOL_LOW;
379
380                 if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
381                         subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_PPOL_LOW;
382
383                 if (v4l2_epn.bus_type == V4L2_MBUS_BT656)
384                         subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_CCIR_CRC |
385                                         ISC_PFE_CFG0_CCIR656;
386
387                 if (mipi_mode)
388                         subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_MIPI;
389
390                 list_add_tail(&subdev_entity->list, &isc->subdev_entities);
391         }
392         of_node_put(epn);
393
394         return ret;
395 }
396
397 static int microchip_xisc_probe(struct platform_device *pdev)
398 {
399         struct device *dev = &pdev->dev;
400         struct isc_device *isc;
401         struct resource *res;
402         void __iomem *io_base;
403         struct isc_subdev_entity *subdev_entity;
404         int irq;
405         int ret;
406         u32 ver;
407
408         isc = devm_kzalloc(dev, sizeof(*isc), GFP_KERNEL);
409         if (!isc)
410                 return -ENOMEM;
411
412         platform_set_drvdata(pdev, isc);
413         isc->dev = dev;
414
415         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
416         io_base = devm_ioremap_resource(dev, res);
417         if (IS_ERR(io_base))
418                 return PTR_ERR(io_base);
419
420         isc->regmap = devm_regmap_init_mmio(dev, io_base, &microchip_isc_regmap_config);
421         if (IS_ERR(isc->regmap)) {
422                 ret = PTR_ERR(isc->regmap);
423                 dev_err(dev, "failed to init register map: %d\n", ret);
424                 return ret;
425         }
426
427         irq = platform_get_irq(pdev, 0);
428         if (irq < 0)
429                 return irq;
430
431         ret = devm_request_irq(dev, irq, microchip_isc_interrupt, 0,
432                                "microchip-sama7g5-xisc", isc);
433         if (ret < 0) {
434                 dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
435                         irq, ret);
436                 return ret;
437         }
438
439         isc->gamma_table = isc_sama7g5_gamma_table;
440         isc->gamma_max = 0;
441
442         isc->max_width = ISC_SAMA7G5_MAX_SUPPORT_WIDTH;
443         isc->max_height = ISC_SAMA7G5_MAX_SUPPORT_HEIGHT;
444
445         isc->config_dpc = isc_sama7g5_config_dpc;
446         isc->config_csc = isc_sama7g5_config_csc;
447         isc->config_cbc = isc_sama7g5_config_cbc;
448         isc->config_cc = isc_sama7g5_config_cc;
449         isc->config_gam = isc_sama7g5_config_gam;
450         isc->config_rlp = isc_sama7g5_config_rlp;
451         isc->config_ctrls = isc_sama7g5_config_ctrls;
452
453         isc->adapt_pipeline = isc_sama7g5_adapt_pipeline;
454
455         isc->offsets.csc = ISC_SAMA7G5_CSC_OFFSET;
456         isc->offsets.cbc = ISC_SAMA7G5_CBC_OFFSET;
457         isc->offsets.sub422 = ISC_SAMA7G5_SUB422_OFFSET;
458         isc->offsets.sub420 = ISC_SAMA7G5_SUB420_OFFSET;
459         isc->offsets.rlp = ISC_SAMA7G5_RLP_OFFSET;
460         isc->offsets.his = ISC_SAMA7G5_HIS_OFFSET;
461         isc->offsets.dma = ISC_SAMA7G5_DMA_OFFSET;
462         isc->offsets.version = ISC_SAMA7G5_VERSION_OFFSET;
463         isc->offsets.his_entry = ISC_SAMA7G5_HIS_ENTRY_OFFSET;
464
465         isc->controller_formats = sama7g5_controller_formats;
466         isc->controller_formats_size = ARRAY_SIZE(sama7g5_controller_formats);
467         isc->formats_list = sama7g5_formats_list;
468         isc->formats_list_size = ARRAY_SIZE(sama7g5_formats_list);
469
470         /* sama7g5-isc RAM access port is full AXI4 - 32 bits per beat */
471         isc->dcfg = ISC_DCFG_YMBSIZE_BEATS32 | ISC_DCFG_CMBSIZE_BEATS32;
472
473         /* sama7g5-isc : ISPCK does not exist, ISC is clocked by MCK */
474         isc->ispck_required = false;
475
476         ret = microchip_isc_pipeline_init(isc);
477         if (ret)
478                 return ret;
479
480         isc->hclock = devm_clk_get(dev, "hclock");
481         if (IS_ERR(isc->hclock)) {
482                 ret = PTR_ERR(isc->hclock);
483                 dev_err(dev, "failed to get hclock: %d\n", ret);
484                 return ret;
485         }
486
487         ret = clk_prepare_enable(isc->hclock);
488         if (ret) {
489                 dev_err(dev, "failed to enable hclock: %d\n", ret);
490                 return ret;
491         }
492
493         ret = microchip_isc_clk_init(isc);
494         if (ret) {
495                 dev_err(dev, "failed to init isc clock: %d\n", ret);
496                 goto unprepare_hclk;
497         }
498
499         ret = v4l2_device_register(dev, &isc->v4l2_dev);
500         if (ret) {
501                 dev_err(dev, "unable to register v4l2 device.\n");
502                 goto unprepare_hclk;
503         }
504
505         ret = xisc_parse_dt(dev, isc);
506         if (ret) {
507                 dev_err(dev, "fail to parse device tree\n");
508                 goto unregister_v4l2_device;
509         }
510
511         if (list_empty(&isc->subdev_entities)) {
512                 dev_err(dev, "no subdev found\n");
513                 ret = -ENODEV;
514                 goto unregister_v4l2_device;
515         }
516
517         list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
518                 struct v4l2_async_subdev *asd;
519                 struct fwnode_handle *fwnode =
520                         of_fwnode_handle(subdev_entity->epn);
521
522                 v4l2_async_nf_init(&subdev_entity->notifier);
523
524                 asd = v4l2_async_nf_add_fwnode_remote(&subdev_entity->notifier,
525                                                       fwnode,
526                                                       struct v4l2_async_subdev);
527
528                 of_node_put(subdev_entity->epn);
529                 subdev_entity->epn = NULL;
530
531                 if (IS_ERR(asd)) {
532                         ret = PTR_ERR(asd);
533                         goto cleanup_subdev;
534                 }
535
536                 subdev_entity->notifier.ops = &microchip_isc_async_ops;
537
538                 ret = v4l2_async_nf_register(&isc->v4l2_dev,
539                                              &subdev_entity->notifier);
540                 if (ret) {
541                         dev_err(dev, "fail to register async notifier\n");
542                         goto cleanup_subdev;
543                 }
544
545                 if (video_is_registered(&isc->video_dev))
546                         break;
547         }
548
549         regmap_read(isc->regmap, ISC_VERSION + isc->offsets.version, &ver);
550
551         ret = isc_mc_init(isc, ver);
552         if (ret < 0)
553                 goto isc_probe_mc_init_err;
554
555         pm_runtime_set_active(dev);
556         pm_runtime_enable(dev);
557         pm_request_idle(dev);
558
559         dev_info(dev, "Microchip XISC version %x\n", ver);
560
561         return 0;
562
563 isc_probe_mc_init_err:
564         isc_mc_cleanup(isc);
565
566 cleanup_subdev:
567         microchip_isc_subdev_cleanup(isc);
568
569 unregister_v4l2_device:
570         v4l2_device_unregister(&isc->v4l2_dev);
571
572 unprepare_hclk:
573         clk_disable_unprepare(isc->hclock);
574
575         microchip_isc_clk_cleanup(isc);
576
577         return ret;
578 }
579
580 static void microchip_xisc_remove(struct platform_device *pdev)
581 {
582         struct isc_device *isc = platform_get_drvdata(pdev);
583
584         pm_runtime_disable(&pdev->dev);
585
586         isc_mc_cleanup(isc);
587
588         microchip_isc_subdev_cleanup(isc);
589
590         v4l2_device_unregister(&isc->v4l2_dev);
591
592         clk_disable_unprepare(isc->hclock);
593
594         microchip_isc_clk_cleanup(isc);
595 }
596
597 static int __maybe_unused xisc_runtime_suspend(struct device *dev)
598 {
599         struct isc_device *isc = dev_get_drvdata(dev);
600
601         clk_disable_unprepare(isc->hclock);
602
603         return 0;
604 }
605
606 static int __maybe_unused xisc_runtime_resume(struct device *dev)
607 {
608         struct isc_device *isc = dev_get_drvdata(dev);
609         int ret;
610
611         ret = clk_prepare_enable(isc->hclock);
612         if (ret)
613                 return ret;
614
615         return ret;
616 }
617
618 static const struct dev_pm_ops microchip_xisc_dev_pm_ops = {
619         SET_RUNTIME_PM_OPS(xisc_runtime_suspend, xisc_runtime_resume, NULL)
620 };
621
622 #if IS_ENABLED(CONFIG_OF)
623 static const struct of_device_id microchip_xisc_of_match[] = {
624         { .compatible = "microchip,sama7g5-isc" },
625         { }
626 };
627 MODULE_DEVICE_TABLE(of, microchip_xisc_of_match);
628 #endif
629
630 static struct platform_driver microchip_xisc_driver = {
631         .probe  = microchip_xisc_probe,
632         .remove_new = microchip_xisc_remove,
633         .driver = {
634                 .name           = "microchip-sama7g5-xisc",
635                 .pm             = &microchip_xisc_dev_pm_ops,
636                 .of_match_table = of_match_ptr(microchip_xisc_of_match),
637         },
638 };
639
640 module_platform_driver(microchip_xisc_driver);
641
642 MODULE_AUTHOR("Eugen Hristev <[email protected]>");
643 MODULE_DESCRIPTION("The V4L2 driver for Microchip-XISC");
644 MODULE_LICENSE("GPL v2");
This page took 0.072351 seconds and 4 git commands to generate.