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_YCYC) == 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 struct fwnode_handle *fwnode =
503 of_fwnode_handle(subdev_entity->epn);
504
505 v4l2_async_nf_init(&subdev_entity->notifier);
506
507 asd = v4l2_async_nf_add_fwnode_remote(&subdev_entity->notifier,
508 fwnode,
509 struct v4l2_async_subdev);
510
511 of_node_put(subdev_entity->epn);
512 subdev_entity->epn = NULL;
513
514 if (IS_ERR(asd)) {
515 ret = PTR_ERR(asd);
516 goto cleanup_subdev;
517 }
518
519 subdev_entity->notifier.ops = &isc_async_ops;
520
521 ret = v4l2_async_nf_register(&isc->v4l2_dev,
522 &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 cleanup_subdev;
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 cleanup_subdev:
560 isc_subdev_cleanup(isc);
561
562 unregister_v4l2_device:
563 v4l2_device_unregister(&isc->v4l2_dev);
564
565 unprepare_hclk:
566 clk_disable_unprepare(isc->hclock);
567
568 isc_clk_cleanup(isc);
569
570 return ret;
571 }
572
atmel_isc_remove(struct platform_device * pdev)573 static int atmel_isc_remove(struct platform_device *pdev)
574 {
575 struct isc_device *isc = platform_get_drvdata(pdev);
576
577 pm_runtime_disable(&pdev->dev);
578
579 isc_subdev_cleanup(isc);
580
581 v4l2_device_unregister(&isc->v4l2_dev);
582
583 clk_disable_unprepare(isc->ispck);
584 clk_disable_unprepare(isc->hclock);
585
586 isc_clk_cleanup(isc);
587
588 return 0;
589 }
590
isc_runtime_suspend(struct device * dev)591 static int __maybe_unused isc_runtime_suspend(struct device *dev)
592 {
593 struct isc_device *isc = dev_get_drvdata(dev);
594
595 clk_disable_unprepare(isc->ispck);
596 clk_disable_unprepare(isc->hclock);
597
598 return 0;
599 }
600
isc_runtime_resume(struct device * dev)601 static int __maybe_unused isc_runtime_resume(struct device *dev)
602 {
603 struct isc_device *isc = dev_get_drvdata(dev);
604 int ret;
605
606 ret = clk_prepare_enable(isc->hclock);
607 if (ret)
608 return ret;
609
610 ret = clk_prepare_enable(isc->ispck);
611 if (ret)
612 clk_disable_unprepare(isc->hclock);
613
614 return ret;
615 }
616
617 static const struct dev_pm_ops atmel_isc_dev_pm_ops = {
618 SET_RUNTIME_PM_OPS(isc_runtime_suspend, isc_runtime_resume, NULL)
619 };
620
621 #if IS_ENABLED(CONFIG_OF)
622 static const struct of_device_id atmel_isc_of_match[] = {
623 { .compatible = "atmel,sama5d2-isc" },
624 { }
625 };
626 MODULE_DEVICE_TABLE(of, atmel_isc_of_match);
627 #endif
628
629 static struct platform_driver atmel_isc_driver = {
630 .probe = atmel_isc_probe,
631 .remove = atmel_isc_remove,
632 .driver = {
633 .name = "atmel-sama5d2-isc",
634 .pm = &atmel_isc_dev_pm_ops,
635 .of_match_table = of_match_ptr(atmel_isc_of_match),
636 },
637 };
638
639 module_platform_driver(atmel_isc_driver);
640
641 MODULE_AUTHOR("Songjun Wu");
642 MODULE_DESCRIPTION("The V4L2 driver for Atmel-ISC");
643 MODULE_LICENSE("GPL v2");
644