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* */
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 .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* */
121 static 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
isc_sama5d2_config_csc(struct isc_device * isc)217 static 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
isc_sama5d2_config_cbc(struct isc_device * isc)236 static 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
isc_sama5d2_config_cc(struct isc_device * isc)246 static 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
isc_sama5d2_config_ctrls(struct isc_device * isc,const struct v4l2_ctrl_ops * ops)259 static 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
isc_sama5d2_config_dpc(struct isc_device * isc)270 static void isc_sama5d2_config_dpc(struct isc_device *isc)
271 {
272 /* This module is not present on sama5d2 pipeline */
273 }
274
isc_sama5d2_config_gam(struct isc_device * isc)275 static void isc_sama5d2_config_gam(struct isc_device *isc)
276 {
277 /* No specific gamma configuration */
278 }
279
isc_sama5d2_config_rlp(struct isc_device * isc)280 static 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
isc_sama5d2_adapt_pipeline(struct isc_device * isc)306 static 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 */
312 static 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
isc_parse_dt(struct device * dev,struct isc_device * isc)353 static 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;
357 struct isc_subdev_entity *subdev_entity;
358 unsigned int flags;
359
360 INIT_LIST_HEAD(&isc->subdev_entities);
361
362 for_each_endpoint_of_node(np, epn) {
363 struct v4l2_fwnode_endpoint v4l2_epn = { .bus_type = 0 };
364 int ret;
365
366 ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(epn),
367 &v4l2_epn);
368 if (ret) {
369 of_node_put(epn);
370 dev_err(dev, "Could not parse the endpoint\n");
371 return -EINVAL;
372 }
373
374 subdev_entity = devm_kzalloc(dev, sizeof(*subdev_entity),
375 GFP_KERNEL);
376 if (!subdev_entity) {
377 of_node_put(epn);
378 return -ENOMEM;
379 }
380 subdev_entity->epn = epn;
381
382 flags = v4l2_epn.bus.parallel.flags;
383
384 if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
385 subdev_entity->pfe_cfg0 = ISC_PFE_CFG0_HPOL_LOW;
386
387 if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
388 subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_VPOL_LOW;
389
390 if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
391 subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_PPOL_LOW;
392
393 if (v4l2_epn.bus_type == V4L2_MBUS_BT656)
394 subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_CCIR_CRC |
395 ISC_PFE_CFG0_CCIR656;
396
397 list_add_tail(&subdev_entity->list, &isc->subdev_entities);
398 }
399
400 return 0;
401 }
402
microchip_isc_probe(struct platform_device * pdev)403 static int microchip_isc_probe(struct platform_device *pdev)
404 {
405 struct device *dev = &pdev->dev;
406 struct isc_device *isc;
407 void __iomem *io_base;
408 struct isc_subdev_entity *subdev_entity;
409 int irq;
410 int ret;
411 u32 ver;
412
413 isc = devm_kzalloc(dev, sizeof(*isc), GFP_KERNEL);
414 if (!isc)
415 return -ENOMEM;
416
417 platform_set_drvdata(pdev, isc);
418 isc->dev = dev;
419
420 io_base = devm_platform_ioremap_resource(pdev, 0);
421 if (IS_ERR(io_base))
422 return PTR_ERR(io_base);
423
424 isc->regmap = devm_regmap_init_mmio(dev, io_base, µchip_isc_regmap_config);
425 if (IS_ERR(isc->regmap)) {
426 ret = PTR_ERR(isc->regmap);
427 dev_err(dev, "failed to init register map: %d\n", ret);
428 return ret;
429 }
430
431 irq = platform_get_irq(pdev, 0);
432 if (irq < 0)
433 return irq;
434
435 ret = devm_request_irq(dev, irq, microchip_isc_interrupt, 0,
436 "microchip-sama5d2-isc", isc);
437 if (ret < 0) {
438 dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
439 irq, ret);
440 return ret;
441 }
442
443 isc->gamma_table = isc_sama5d2_gamma_table;
444 isc->gamma_max = 2;
445
446 isc->max_width = ISC_SAMA5D2_MAX_SUPPORT_WIDTH;
447 isc->max_height = ISC_SAMA5D2_MAX_SUPPORT_HEIGHT;
448
449 isc->config_dpc = isc_sama5d2_config_dpc;
450 isc->config_csc = isc_sama5d2_config_csc;
451 isc->config_cbc = isc_sama5d2_config_cbc;
452 isc->config_cc = isc_sama5d2_config_cc;
453 isc->config_gam = isc_sama5d2_config_gam;
454 isc->config_rlp = isc_sama5d2_config_rlp;
455 isc->config_ctrls = isc_sama5d2_config_ctrls;
456
457 isc->adapt_pipeline = isc_sama5d2_adapt_pipeline;
458
459 isc->offsets.csc = ISC_SAMA5D2_CSC_OFFSET;
460 isc->offsets.cbc = ISC_SAMA5D2_CBC_OFFSET;
461 isc->offsets.sub422 = ISC_SAMA5D2_SUB422_OFFSET;
462 isc->offsets.sub420 = ISC_SAMA5D2_SUB420_OFFSET;
463 isc->offsets.rlp = ISC_SAMA5D2_RLP_OFFSET;
464 isc->offsets.his = ISC_SAMA5D2_HIS_OFFSET;
465 isc->offsets.dma = ISC_SAMA5D2_DMA_OFFSET;
466 isc->offsets.version = ISC_SAMA5D2_VERSION_OFFSET;
467 isc->offsets.his_entry = ISC_SAMA5D2_HIS_ENTRY_OFFSET;
468
469 isc->controller_formats = sama5d2_controller_formats;
470 isc->controller_formats_size = ARRAY_SIZE(sama5d2_controller_formats);
471 isc->formats_list = sama5d2_formats_list;
472 isc->formats_list_size = ARRAY_SIZE(sama5d2_formats_list);
473
474 /* sama5d2-isc - 8 bits per beat */
475 isc->dcfg = ISC_DCFG_YMBSIZE_BEATS8 | ISC_DCFG_CMBSIZE_BEATS8;
476
477 /* sama5d2-isc : ISPCK is required and mandatory */
478 isc->ispck_required = true;
479
480 ret = microchip_isc_pipeline_init(isc);
481 if (ret)
482 return ret;
483
484 isc->hclock = devm_clk_get(dev, "hclock");
485 if (IS_ERR(isc->hclock)) {
486 ret = PTR_ERR(isc->hclock);
487 dev_err(dev, "failed to get hclock: %d\n", ret);
488 return ret;
489 }
490
491 ret = clk_prepare_enable(isc->hclock);
492 if (ret) {
493 dev_err(dev, "failed to enable hclock: %d\n", ret);
494 return ret;
495 }
496
497 ret = microchip_isc_clk_init(isc);
498 if (ret) {
499 dev_err(dev, "failed to init isc clock: %d\n", ret);
500 goto unprepare_hclk;
501 }
502 ret = v4l2_device_register(dev, &isc->v4l2_dev);
503 if (ret) {
504 dev_err(dev, "unable to register v4l2 device.\n");
505 goto unprepare_clk;
506 }
507
508 ret = isc_parse_dt(dev, isc);
509 if (ret) {
510 dev_err(dev, "fail to parse device tree\n");
511 goto unregister_v4l2_device;
512 }
513
514 if (list_empty(&isc->subdev_entities)) {
515 dev_err(dev, "no subdev found\n");
516 ret = -ENODEV;
517 goto unregister_v4l2_device;
518 }
519
520 list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
521 struct v4l2_async_connection *asd;
522 struct fwnode_handle *fwnode =
523 of_fwnode_handle(subdev_entity->epn);
524
525 v4l2_async_nf_init(&subdev_entity->notifier, &isc->v4l2_dev);
526
527 asd = v4l2_async_nf_add_fwnode_remote(&subdev_entity->notifier,
528 fwnode,
529 struct v4l2_async_connection);
530
531 of_node_put(subdev_entity->epn);
532 subdev_entity->epn = NULL;
533
534 if (IS_ERR(asd)) {
535 ret = PTR_ERR(asd);
536 goto cleanup_subdev;
537 }
538
539 subdev_entity->notifier.ops = µchip_isc_async_ops;
540
541 ret = v4l2_async_nf_register(&subdev_entity->notifier);
542 if (ret) {
543 dev_err(dev, "fail to register async notifier\n");
544 goto cleanup_subdev;
545 }
546
547 if (video_is_registered(&isc->video_dev))
548 break;
549 }
550
551 regmap_read(isc->regmap, ISC_VERSION + isc->offsets.version, &ver);
552
553 ret = isc_mc_init(isc, ver);
554 if (ret < 0)
555 goto isc_probe_mc_init_err;
556
557 pm_runtime_set_active(dev);
558 pm_runtime_enable(dev);
559 pm_request_idle(dev);
560
561 isc->ispck = isc->isc_clks[ISC_ISPCK].clk;
562
563 ret = clk_prepare_enable(isc->ispck);
564 if (ret) {
565 dev_err(dev, "failed to enable ispck: %d\n", ret);
566 goto disable_pm;
567 }
568
569 /* ispck should be greater or equal to hclock */
570 ret = clk_set_rate(isc->ispck, clk_get_rate(isc->hclock));
571 if (ret) {
572 dev_err(dev, "failed to set ispck rate: %d\n", ret);
573 goto unprepare_clk;
574 }
575
576 dev_info(dev, "Microchip ISC version %x\n", ver);
577
578 return 0;
579
580 unprepare_clk:
581 clk_disable_unprepare(isc->ispck);
582
583 disable_pm:
584 pm_runtime_disable(dev);
585
586 isc_probe_mc_init_err:
587 isc_mc_cleanup(isc);
588
589 cleanup_subdev:
590 microchip_isc_subdev_cleanup(isc);
591
592 unregister_v4l2_device:
593 v4l2_device_unregister(&isc->v4l2_dev);
594
595 unprepare_hclk:
596 clk_disable_unprepare(isc->hclock);
597
598 microchip_isc_clk_cleanup(isc);
599
600 return ret;
601 }
602
microchip_isc_remove(struct platform_device * pdev)603 static void microchip_isc_remove(struct platform_device *pdev)
604 {
605 struct isc_device *isc = platform_get_drvdata(pdev);
606
607 pm_runtime_disable(&pdev->dev);
608
609 isc_mc_cleanup(isc);
610
611 microchip_isc_subdev_cleanup(isc);
612
613 v4l2_device_unregister(&isc->v4l2_dev);
614
615 clk_disable_unprepare(isc->ispck);
616 clk_disable_unprepare(isc->hclock);
617
618 microchip_isc_clk_cleanup(isc);
619 }
620
isc_runtime_suspend(struct device * dev)621 static int __maybe_unused isc_runtime_suspend(struct device *dev)
622 {
623 struct isc_device *isc = dev_get_drvdata(dev);
624
625 clk_disable_unprepare(isc->ispck);
626 clk_disable_unprepare(isc->hclock);
627
628 return 0;
629 }
630
isc_runtime_resume(struct device * dev)631 static int __maybe_unused isc_runtime_resume(struct device *dev)
632 {
633 struct isc_device *isc = dev_get_drvdata(dev);
634 int ret;
635
636 ret = clk_prepare_enable(isc->hclock);
637 if (ret)
638 return ret;
639
640 ret = clk_prepare_enable(isc->ispck);
641 if (ret)
642 clk_disable_unprepare(isc->hclock);
643
644 return ret;
645 }
646
647 static const struct dev_pm_ops microchip_isc_dev_pm_ops = {
648 SET_RUNTIME_PM_OPS(isc_runtime_suspend, isc_runtime_resume, NULL)
649 };
650
651 #if IS_ENABLED(CONFIG_OF)
652 static const struct of_device_id microchip_isc_of_match[] = {
653 { .compatible = "atmel,sama5d2-isc" },
654 { }
655 };
656 MODULE_DEVICE_TABLE(of, microchip_isc_of_match);
657 #endif
658
659 static struct platform_driver microchip_isc_driver = {
660 .probe = microchip_isc_probe,
661 .remove = microchip_isc_remove,
662 .driver = {
663 .name = "microchip-sama5d2-isc",
664 .pm = µchip_isc_dev_pm_ops,
665 .of_match_table = of_match_ptr(microchip_isc_of_match),
666 },
667 };
668
669 module_platform_driver(microchip_isc_driver);
670
671 MODULE_AUTHOR("Songjun Wu");
672 MODULE_DESCRIPTION("The V4L2 driver for Microchip-ISC");
673 MODULE_LICENSE("GPL v2");
674