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 ret = isc_pipeline_init(isc);
458 if (ret)
459 return ret;
460
461 isc->hclock = devm_clk_get(dev, "hclock");
462 if (IS_ERR(isc->hclock)) {
463 ret = PTR_ERR(isc->hclock);
464 dev_err(dev, "failed to get hclock: %d\n", ret);
465 return ret;
466 }
467
468 ret = clk_prepare_enable(isc->hclock);
469 if (ret) {
470 dev_err(dev, "failed to enable hclock: %d\n", ret);
471 return ret;
472 }
473
474 ret = isc_clk_init(isc);
475 if (ret) {
476 dev_err(dev, "failed to init isc clock: %d\n", ret);
477 goto unprepare_hclk;
478 }
479
480 isc->ispck = isc->isc_clks[ISC_ISPCK].clk;
481
482 ret = clk_prepare_enable(isc->ispck);
483 if (ret) {
484 dev_err(dev, "failed to enable ispck: %d\n", ret);
485 goto unprepare_hclk;
486 }
487
488 /* ispck should be greater or equal to hclock */
489 ret = clk_set_rate(isc->ispck, clk_get_rate(isc->hclock));
490 if (ret) {
491 dev_err(dev, "failed to set ispck rate: %d\n", ret);
492 goto unprepare_clk;
493 }
494
495 ret = v4l2_device_register(dev, &isc->v4l2_dev);
496 if (ret) {
497 dev_err(dev, "unable to register v4l2 device.\n");
498 goto unprepare_clk;
499 }
500
501 ret = isc_parse_dt(dev, isc);
502 if (ret) {
503 dev_err(dev, "fail to parse device tree\n");
504 goto unregister_v4l2_device;
505 }
506
507 if (list_empty(&isc->subdev_entities)) {
508 dev_err(dev, "no subdev found\n");
509 ret = -ENODEV;
510 goto unregister_v4l2_device;
511 }
512
513 list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
514 struct v4l2_async_subdev *asd;
515
516 v4l2_async_notifier_init(&subdev_entity->notifier);
517
518 asd = v4l2_async_notifier_add_fwnode_remote_subdev(
519 &subdev_entity->notifier,
520 of_fwnode_handle(subdev_entity->epn),
521 struct v4l2_async_subdev);
522
523 of_node_put(subdev_entity->epn);
524 subdev_entity->epn = NULL;
525
526 if (IS_ERR(asd)) {
527 ret = PTR_ERR(asd);
528 goto cleanup_subdev;
529 }
530
531 subdev_entity->notifier.ops = &isc_async_ops;
532
533 ret = v4l2_async_notifier_register(&isc->v4l2_dev,
534 &subdev_entity->notifier);
535 if (ret) {
536 dev_err(dev, "fail to register async notifier\n");
537 goto cleanup_subdev;
538 }
539
540 if (video_is_registered(&isc->video_dev))
541 break;
542 }
543
544 pm_runtime_set_active(dev);
545 pm_runtime_enable(dev);
546 pm_request_idle(dev);
547
548 regmap_read(isc->regmap, ISC_VERSION + isc->offsets.version, &ver);
549 dev_info(dev, "Microchip ISC version %x\n", ver);
550
551 return 0;
552
553 cleanup_subdev:
554 isc_subdev_cleanup(isc);
555
556 unregister_v4l2_device:
557 v4l2_device_unregister(&isc->v4l2_dev);
558
559 unprepare_clk:
560 clk_disable_unprepare(isc->ispck);
561 unprepare_hclk:
562 clk_disable_unprepare(isc->hclock);
563
564 isc_clk_cleanup(isc);
565
566 return ret;
567 }
568
atmel_isc_remove(struct platform_device * pdev)569 static int atmel_isc_remove(struct platform_device *pdev)
570 {
571 struct isc_device *isc = platform_get_drvdata(pdev);
572
573 pm_runtime_disable(&pdev->dev);
574
575 isc_subdev_cleanup(isc);
576
577 v4l2_device_unregister(&isc->v4l2_dev);
578
579 clk_disable_unprepare(isc->ispck);
580 clk_disable_unprepare(isc->hclock);
581
582 isc_clk_cleanup(isc);
583
584 return 0;
585 }
586
isc_runtime_suspend(struct device * dev)587 static int __maybe_unused isc_runtime_suspend(struct device *dev)
588 {
589 struct isc_device *isc = dev_get_drvdata(dev);
590
591 clk_disable_unprepare(isc->ispck);
592 clk_disable_unprepare(isc->hclock);
593
594 return 0;
595 }
596
isc_runtime_resume(struct device * dev)597 static int __maybe_unused isc_runtime_resume(struct device *dev)
598 {
599 struct isc_device *isc = dev_get_drvdata(dev);
600 int ret;
601
602 ret = clk_prepare_enable(isc->hclock);
603 if (ret)
604 return ret;
605
606 ret = clk_prepare_enable(isc->ispck);
607 if (ret)
608 clk_disable_unprepare(isc->hclock);
609
610 return ret;
611 }
612
613 static const struct dev_pm_ops atmel_isc_dev_pm_ops = {
614 SET_RUNTIME_PM_OPS(isc_runtime_suspend, isc_runtime_resume, NULL)
615 };
616
617 #if IS_ENABLED(CONFIG_OF)
618 static const struct of_device_id atmel_isc_of_match[] = {
619 { .compatible = "atmel,sama5d2-isc" },
620 { }
621 };
622 MODULE_DEVICE_TABLE(of, atmel_isc_of_match);
623 #endif
624
625 static struct platform_driver atmel_isc_driver = {
626 .probe = atmel_isc_probe,
627 .remove = atmel_isc_remove,
628 .driver = {
629 .name = "atmel-sama5d2-isc",
630 .pm = &atmel_isc_dev_pm_ops,
631 .of_match_table = of_match_ptr(atmel_isc_of_match),
632 },
633 };
634
635 module_platform_driver(atmel_isc_driver);
636
637 MODULE_AUTHOR("Songjun Wu");
638 MODULE_DESCRIPTION("The V4L2 driver for Atmel-ISC");
639 MODULE_LICENSE("GPL v2");
640