]> Git Repo - linux.git/blob - drivers/media/platform/microchip/microchip-sama7g5-isc.c
Linux 6.14-rc3
[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;
340         struct isc_subdev_entity *subdev_entity;
341         unsigned int flags;
342         bool mipi_mode;
343
344         INIT_LIST_HEAD(&isc->subdev_entities);
345
346         mipi_mode = of_property_read_bool(np, "microchip,mipi-mode");
347
348         for_each_endpoint_of_node(np, epn) {
349                 struct v4l2_fwnode_endpoint v4l2_epn = { .bus_type = 0 };
350                 int ret;
351
352                 ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(epn),
353                                                  &v4l2_epn);
354                 if (ret) {
355                         of_node_put(epn);
356                         dev_err(dev, "Could not parse the endpoint\n");
357                         return -EINVAL;
358                 }
359
360                 subdev_entity = devm_kzalloc(dev, sizeof(*subdev_entity),
361                                              GFP_KERNEL);
362                 if (!subdev_entity) {
363                         of_node_put(epn);
364                         return -ENOMEM;
365                 }
366                 subdev_entity->epn = epn;
367
368                 flags = v4l2_epn.bus.parallel.flags;
369
370                 if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
371                         subdev_entity->pfe_cfg0 = ISC_PFE_CFG0_HPOL_LOW;
372
373                 if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
374                         subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_VPOL_LOW;
375
376                 if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
377                         subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_PPOL_LOW;
378
379                 if (v4l2_epn.bus_type == V4L2_MBUS_BT656)
380                         subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_CCIR_CRC |
381                                         ISC_PFE_CFG0_CCIR656;
382
383                 if (mipi_mode)
384                         subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_MIPI;
385
386                 list_add_tail(&subdev_entity->list, &isc->subdev_entities);
387         }
388
389         return 0;
390 }
391
392 static int microchip_xisc_probe(struct platform_device *pdev)
393 {
394         struct device *dev = &pdev->dev;
395         struct isc_device *isc;
396         void __iomem *io_base;
397         struct isc_subdev_entity *subdev_entity;
398         int irq;
399         int ret;
400         u32 ver;
401
402         isc = devm_kzalloc(dev, sizeof(*isc), GFP_KERNEL);
403         if (!isc)
404                 return -ENOMEM;
405
406         platform_set_drvdata(pdev, isc);
407         isc->dev = dev;
408
409         io_base = devm_platform_ioremap_resource(pdev, 0);
410         if (IS_ERR(io_base))
411                 return PTR_ERR(io_base);
412
413         isc->regmap = devm_regmap_init_mmio(dev, io_base, &microchip_isc_regmap_config);
414         if (IS_ERR(isc->regmap)) {
415                 ret = PTR_ERR(isc->regmap);
416                 dev_err(dev, "failed to init register map: %d\n", ret);
417                 return ret;
418         }
419
420         irq = platform_get_irq(pdev, 0);
421         if (irq < 0)
422                 return irq;
423
424         ret = devm_request_irq(dev, irq, microchip_isc_interrupt, 0,
425                                "microchip-sama7g5-xisc", isc);
426         if (ret < 0) {
427                 dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
428                         irq, ret);
429                 return ret;
430         }
431
432         isc->gamma_table = isc_sama7g5_gamma_table;
433         isc->gamma_max = 0;
434
435         isc->max_width = ISC_SAMA7G5_MAX_SUPPORT_WIDTH;
436         isc->max_height = ISC_SAMA7G5_MAX_SUPPORT_HEIGHT;
437
438         isc->config_dpc = isc_sama7g5_config_dpc;
439         isc->config_csc = isc_sama7g5_config_csc;
440         isc->config_cbc = isc_sama7g5_config_cbc;
441         isc->config_cc = isc_sama7g5_config_cc;
442         isc->config_gam = isc_sama7g5_config_gam;
443         isc->config_rlp = isc_sama7g5_config_rlp;
444         isc->config_ctrls = isc_sama7g5_config_ctrls;
445
446         isc->adapt_pipeline = isc_sama7g5_adapt_pipeline;
447
448         isc->offsets.csc = ISC_SAMA7G5_CSC_OFFSET;
449         isc->offsets.cbc = ISC_SAMA7G5_CBC_OFFSET;
450         isc->offsets.sub422 = ISC_SAMA7G5_SUB422_OFFSET;
451         isc->offsets.sub420 = ISC_SAMA7G5_SUB420_OFFSET;
452         isc->offsets.rlp = ISC_SAMA7G5_RLP_OFFSET;
453         isc->offsets.his = ISC_SAMA7G5_HIS_OFFSET;
454         isc->offsets.dma = ISC_SAMA7G5_DMA_OFFSET;
455         isc->offsets.version = ISC_SAMA7G5_VERSION_OFFSET;
456         isc->offsets.his_entry = ISC_SAMA7G5_HIS_ENTRY_OFFSET;
457
458         isc->controller_formats = sama7g5_controller_formats;
459         isc->controller_formats_size = ARRAY_SIZE(sama7g5_controller_formats);
460         isc->formats_list = sama7g5_formats_list;
461         isc->formats_list_size = ARRAY_SIZE(sama7g5_formats_list);
462
463         /* sama7g5-isc RAM access port is full AXI4 - 32 bits per beat */
464         isc->dcfg = ISC_DCFG_YMBSIZE_BEATS32 | ISC_DCFG_CMBSIZE_BEATS32;
465
466         /* sama7g5-isc : ISPCK does not exist, ISC is clocked by MCK */
467         isc->ispck_required = false;
468
469         ret = microchip_isc_pipeline_init(isc);
470         if (ret)
471                 return ret;
472
473         isc->hclock = devm_clk_get(dev, "hclock");
474         if (IS_ERR(isc->hclock)) {
475                 ret = PTR_ERR(isc->hclock);
476                 dev_err(dev, "failed to get hclock: %d\n", ret);
477                 return ret;
478         }
479
480         ret = clk_prepare_enable(isc->hclock);
481         if (ret) {
482                 dev_err(dev, "failed to enable hclock: %d\n", ret);
483                 return ret;
484         }
485
486         ret = microchip_isc_clk_init(isc);
487         if (ret) {
488                 dev_err(dev, "failed to init isc clock: %d\n", ret);
489                 goto unprepare_hclk;
490         }
491
492         ret = v4l2_device_register(dev, &isc->v4l2_dev);
493         if (ret) {
494                 dev_err(dev, "unable to register v4l2 device.\n");
495                 goto unprepare_hclk;
496         }
497
498         ret = xisc_parse_dt(dev, isc);
499         if (ret) {
500                 dev_err(dev, "fail to parse device tree\n");
501                 goto unregister_v4l2_device;
502         }
503
504         if (list_empty(&isc->subdev_entities)) {
505                 dev_err(dev, "no subdev found\n");
506                 ret = -ENODEV;
507                 goto unregister_v4l2_device;
508         }
509
510         list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
511                 struct v4l2_async_connection *asd;
512                 struct fwnode_handle *fwnode =
513                         of_fwnode_handle(subdev_entity->epn);
514
515                 v4l2_async_nf_init(&subdev_entity->notifier, &isc->v4l2_dev);
516
517                 asd = v4l2_async_nf_add_fwnode_remote(&subdev_entity->notifier,
518                                                       fwnode,
519                                                       struct v4l2_async_connection);
520
521                 of_node_put(subdev_entity->epn);
522                 subdev_entity->epn = NULL;
523
524                 if (IS_ERR(asd)) {
525                         ret = PTR_ERR(asd);
526                         goto cleanup_subdev;
527                 }
528
529                 subdev_entity->notifier.ops = &microchip_isc_async_ops;
530
531                 ret = v4l2_async_nf_register(&subdev_entity->notifier);
532                 if (ret) {
533                         dev_err(dev, "fail to register async notifier\n");
534                         goto cleanup_subdev;
535                 }
536
537                 if (video_is_registered(&isc->video_dev))
538                         break;
539         }
540
541         regmap_read(isc->regmap, ISC_VERSION + isc->offsets.version, &ver);
542
543         ret = isc_mc_init(isc, ver);
544         if (ret < 0)
545                 goto isc_probe_mc_init_err;
546
547         pm_runtime_set_active(dev);
548         pm_runtime_enable(dev);
549         pm_request_idle(dev);
550
551         dev_info(dev, "Microchip XISC version %x\n", ver);
552
553         return 0;
554
555 isc_probe_mc_init_err:
556         isc_mc_cleanup(isc);
557
558 cleanup_subdev:
559         microchip_isc_subdev_cleanup(isc);
560
561 unregister_v4l2_device:
562         v4l2_device_unregister(&isc->v4l2_dev);
563
564 unprepare_hclk:
565         clk_disable_unprepare(isc->hclock);
566
567         microchip_isc_clk_cleanup(isc);
568
569         return ret;
570 }
571
572 static void microchip_xisc_remove(struct platform_device *pdev)
573 {
574         struct isc_device *isc = platform_get_drvdata(pdev);
575
576         pm_runtime_disable(&pdev->dev);
577
578         isc_mc_cleanup(isc);
579
580         microchip_isc_subdev_cleanup(isc);
581
582         v4l2_device_unregister(&isc->v4l2_dev);
583
584         clk_disable_unprepare(isc->hclock);
585
586         microchip_isc_clk_cleanup(isc);
587 }
588
589 static int __maybe_unused xisc_runtime_suspend(struct device *dev)
590 {
591         struct isc_device *isc = dev_get_drvdata(dev);
592
593         clk_disable_unprepare(isc->hclock);
594
595         return 0;
596 }
597
598 static int __maybe_unused xisc_runtime_resume(struct device *dev)
599 {
600         struct isc_device *isc = dev_get_drvdata(dev);
601         int ret;
602
603         ret = clk_prepare_enable(isc->hclock);
604         if (ret)
605                 return ret;
606
607         return ret;
608 }
609
610 static const struct dev_pm_ops microchip_xisc_dev_pm_ops = {
611         SET_RUNTIME_PM_OPS(xisc_runtime_suspend, xisc_runtime_resume, NULL)
612 };
613
614 #if IS_ENABLED(CONFIG_OF)
615 static const struct of_device_id microchip_xisc_of_match[] = {
616         { .compatible = "microchip,sama7g5-isc" },
617         { }
618 };
619 MODULE_DEVICE_TABLE(of, microchip_xisc_of_match);
620 #endif
621
622 static struct platform_driver microchip_xisc_driver = {
623         .probe  = microchip_xisc_probe,
624         .remove = microchip_xisc_remove,
625         .driver = {
626                 .name           = "microchip-sama7g5-xisc",
627                 .pm             = &microchip_xisc_dev_pm_ops,
628                 .of_match_table = of_match_ptr(microchip_xisc_of_match),
629         },
630 };
631
632 module_platform_driver(microchip_xisc_driver);
633
634 MODULE_AUTHOR("Eugen Hristev <[email protected]>");
635 MODULE_DESCRIPTION("The V4L2 driver for Microchip-XISC");
636 MODULE_LICENSE("GPL v2");
This page took 0.068096 seconds and 4 git commands to generate.