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