Loading...
Note: File does not exist in v4.6.
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Microchip Image Sensor Controller (ISC) driver
4 *
5 * Copyright (C) 2016-2019 Microchip Technology, Inc.
6 *
7 * Author: Songjun Wu
8 * Author: Eugen Hristev <eugen.hristev@microchip.com>
9 *
10 *
11 * Sensor-->PFE-->WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB-->RLP-->DMA
12 *
13 * ISC video pipeline integrates the following submodules:
14 * PFE: Parallel Front End to sample the camera sensor input stream
15 * WB: Programmable white balance in the Bayer domain
16 * CFA: Color filter array interpolation module
17 * CC: Programmable color correction
18 * GAM: Gamma correction
19 * CSC: Programmable color space conversion
20 * CBC: Contrast and Brightness control
21 * SUB: This module performs YCbCr444 to YCbCr420 chrominance subsampling
22 * RLP: This module performs rounding, range limiting
23 * and packing of the incoming data
24 */
25
26#include <linux/clk.h>
27#include <linux/clkdev.h>
28#include <linux/clk-provider.h>
29#include <linux/delay.h>
30#include <linux/interrupt.h>
31#include <linux/math64.h>
32#include <linux/module.h>
33#include <linux/of.h>
34#include <linux/of_graph.h>
35#include <linux/platform_device.h>
36#include <linux/pm_runtime.h>
37#include <linux/regmap.h>
38#include <linux/videodev2.h>
39
40#include <media/v4l2-ctrls.h>
41#include <media/v4l2-device.h>
42#include <media/v4l2-event.h>
43#include <media/v4l2-image-sizes.h>
44#include <media/v4l2-ioctl.h>
45#include <media/v4l2-fwnode.h>
46#include <media/v4l2-subdev.h>
47#include <media/videobuf2-dma-contig.h>
48
49#include "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* */
60static 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* */
121static 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
217static 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
236static 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
246static 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
259static 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
270static void isc_sama5d2_config_dpc(struct isc_device *isc)
271{
272 /* This module is not present on sama5d2 pipeline */
273}
274
275static void isc_sama5d2_config_gam(struct isc_device *isc)
276{
277 /* No specific gamma configuration */
278}
279
280static 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
306static 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 */
312static 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
353static 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
408static 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, µchip_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 = µchip_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
588unprepare_clk:
589 clk_disable_unprepare(isc->ispck);
590
591disable_pm:
592 pm_runtime_disable(dev);
593
594isc_probe_mc_init_err:
595 isc_mc_cleanup(isc);
596
597cleanup_subdev:
598 microchip_isc_subdev_cleanup(isc);
599
600unregister_v4l2_device:
601 v4l2_device_unregister(&isc->v4l2_dev);
602
603unprepare_hclk:
604 clk_disable_unprepare(isc->hclock);
605
606 microchip_isc_clk_cleanup(isc);
607
608 return ret;
609}
610
611static int 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 return 0;
629}
630
631static int __maybe_unused isc_runtime_suspend(struct device *dev)
632{
633 struct isc_device *isc = dev_get_drvdata(dev);
634
635 clk_disable_unprepare(isc->ispck);
636 clk_disable_unprepare(isc->hclock);
637
638 return 0;
639}
640
641static int __maybe_unused isc_runtime_resume(struct device *dev)
642{
643 struct isc_device *isc = dev_get_drvdata(dev);
644 int ret;
645
646 ret = clk_prepare_enable(isc->hclock);
647 if (ret)
648 return ret;
649
650 ret = clk_prepare_enable(isc->ispck);
651 if (ret)
652 clk_disable_unprepare(isc->hclock);
653
654 return ret;
655}
656
657static const struct dev_pm_ops microchip_isc_dev_pm_ops = {
658 SET_RUNTIME_PM_OPS(isc_runtime_suspend, isc_runtime_resume, NULL)
659};
660
661#if IS_ENABLED(CONFIG_OF)
662static const struct of_device_id microchip_isc_of_match[] = {
663 { .compatible = "atmel,sama5d2-isc" },
664 { }
665};
666MODULE_DEVICE_TABLE(of, microchip_isc_of_match);
667#endif
668
669static struct platform_driver microchip_isc_driver = {
670 .probe = microchip_isc_probe,
671 .remove = microchip_isc_remove,
672 .driver = {
673 .name = "microchip-sama5d2-isc",
674 .pm = µchip_isc_dev_pm_ops,
675 .of_match_table = of_match_ptr(microchip_isc_of_match),
676 },
677};
678
679module_platform_driver(microchip_isc_driver);
680
681MODULE_AUTHOR("Songjun Wu");
682MODULE_DESCRIPTION("The V4L2 driver for Microchip-ISC");
683MODULE_LICENSE("GPL v2");