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