1 // SPDX-License-Identifier: GPL-2.0
3 * Microchip Image Sensor Controller (ISC) driver
5 * Copyright (C) 2016-2019 Microchip Technology, Inc.
8 * Author: Eugen Hristev <eugen.hristev@microchip.com>
11 * Sensor-->PFE-->WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB-->RLP-->DMA
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
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>
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>
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>
49 #include "atmel-isc-regs.h"
50 #include "atmel-isc.h"
52 #define ISC_SAMA5D2_MAX_SUPPORT_WIDTH 2592
53 #define ISC_SAMA5D2_MAX_SUPPORT_HEIGHT 1944
55 #define ISC_SAMA5D2_PIPELINE \
56 (WB_ENABLE | CFA_ENABLE | CC_ENABLE | GAM_ENABLES | CSC_ENABLE | \
57 CBC_ENABLE | SUB422_ENABLE | SUB420_ENABLE)
59 /* This is a list of the formats that the ISC can *output* */
60 static const struct isc_format sama5d2_controller_formats[] = {
62 .fourcc = V4L2_PIX_FMT_ARGB444,
64 .fourcc = V4L2_PIX_FMT_ARGB555,
66 .fourcc = V4L2_PIX_FMT_RGB565,
68 .fourcc = V4L2_PIX_FMT_ABGR32,
70 .fourcc = V4L2_PIX_FMT_XBGR32,
72 .fourcc = V4L2_PIX_FMT_YUV420,
74 .fourcc = V4L2_PIX_FMT_YUYV,
76 .fourcc = V4L2_PIX_FMT_YUV422P,
78 .fourcc = V4L2_PIX_FMT_GREY,
80 .fourcc = V4L2_PIX_FMT_Y10,
82 .fourcc = V4L2_PIX_FMT_SBGGR8,
84 .fourcc = V4L2_PIX_FMT_SGBRG8,
86 .fourcc = V4L2_PIX_FMT_SGRBG8,
88 .fourcc = V4L2_PIX_FMT_SRGGB8,
90 .fourcc = V4L2_PIX_FMT_SBGGR10,
92 .fourcc = V4L2_PIX_FMT_SGBRG10,
94 .fourcc = V4L2_PIX_FMT_SGRBG10,
96 .fourcc = V4L2_PIX_FMT_SRGGB10,
100 /* This is a list of formats that the ISC can receive as *input* */
101 static struct isc_format sama5d2_formats_list[] = {
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
175 .fourcc = V4L2_PIX_FMT_GREY,
176 .mbus_code = MEDIA_BUS_FMT_Y8_1X8,
177 .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
180 .fourcc = V4L2_PIX_FMT_YUYV,
181 .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
182 .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
185 .fourcc = V4L2_PIX_FMT_RGB565,
186 .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE,
187 .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
190 .fourcc = V4L2_PIX_FMT_Y10,
191 .mbus_code = MEDIA_BUS_FMT_Y10_1X10,
192 .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
197 static void isc_sama5d2_config_csc(struct isc_device *isc)
199 struct regmap *regmap = isc->regmap;
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));
216 static void isc_sama5d2_config_cbc(struct isc_device *isc)
218 struct regmap *regmap = isc->regmap;
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);
226 static void isc_sama5d2_config_cc(struct isc_device *isc)
228 struct regmap *regmap = isc->regmap;
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));
239 static void isc_sama5d2_config_ctrls(struct isc_device *isc,
240 const struct v4l2_ctrl_ops *ops)
242 struct isc_ctrls *ctrls = &isc->ctrls;
243 struct v4l2_ctrl_handler *hdl = &ctrls->handler;
245 ctrls->contrast = 256;
247 v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -2048, 2047, 1, 256);
250 static void isc_sama5d2_config_dpc(struct isc_device *isc)
252 /* This module is not present on sama5d2 pipeline */
255 static void isc_sama5d2_config_gam(struct isc_device *isc)
257 /* No specific gamma configuration */
260 static void isc_sama5d2_config_rlp(struct isc_device *isc)
262 struct regmap *regmap = isc->regmap;
263 u32 rlp_mode = isc->config.rlp_cfg_mode;
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.
274 * Thus, if the YCYC mode is selected, replace it with the
275 * sama5d2-compliant mode which is YYCC .
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;
282 regmap_update_bits(regmap, ISC_RLP_CFG + isc->offsets.rlp,
283 ISC_RLP_CFG_MODE_MASK, rlp_mode);
286 static void isc_sama5d2_adapt_pipeline(struct isc_device *isc)
288 isc->try_config.bits_pipeline &= ISC_SAMA5D2_PIPELINE;
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 },
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 },
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 },
333 static int isc_parse_dt(struct device *dev, struct isc_device *isc)
335 struct device_node *np = dev->of_node;
336 struct device_node *epn = NULL;
337 struct isc_subdev_entity *subdev_entity;
341 INIT_LIST_HEAD(&isc->subdev_entities);
344 struct v4l2_fwnode_endpoint v4l2_epn = { .bus_type = 0 };
346 epn = of_graph_get_next_endpoint(np, epn);
350 ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(epn),
354 dev_err(dev, "Could not parse the endpoint\n");
358 subdev_entity = devm_kzalloc(dev, sizeof(*subdev_entity),
360 if (!subdev_entity) {
364 subdev_entity->epn = epn;
366 flags = v4l2_epn.bus.parallel.flags;
368 if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
369 subdev_entity->pfe_cfg0 = ISC_PFE_CFG0_HPOL_LOW;
371 if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
372 subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_VPOL_LOW;
374 if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
375 subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_PPOL_LOW;
377 if (v4l2_epn.bus_type == V4L2_MBUS_BT656)
378 subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_CCIR_CRC |
379 ISC_PFE_CFG0_CCIR656;
381 list_add_tail(&subdev_entity->list, &isc->subdev_entities);
388 static int atmel_isc_probe(struct platform_device *pdev)
390 struct device *dev = &pdev->dev;
391 struct isc_device *isc;
392 struct resource *res;
393 void __iomem *io_base;
394 struct isc_subdev_entity *subdev_entity;
399 isc = devm_kzalloc(dev, sizeof(*isc), GFP_KERNEL);
403 platform_set_drvdata(pdev, isc);
406 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
407 io_base = devm_ioremap_resource(dev, res);
409 return PTR_ERR(io_base);
411 isc->regmap = devm_regmap_init_mmio(dev, io_base, &isc_regmap_config);
412 if (IS_ERR(isc->regmap)) {
413 ret = PTR_ERR(isc->regmap);
414 dev_err(dev, "failed to init register map: %d\n", ret);
418 irq = platform_get_irq(pdev, 0);
422 ret = devm_request_irq(dev, irq, isc_interrupt, 0,
423 "atmel-sama5d2-isc", isc);
425 dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
430 isc->gamma_table = isc_sama5d2_gamma_table;
433 isc->max_width = ISC_SAMA5D2_MAX_SUPPORT_WIDTH;
434 isc->max_height = ISC_SAMA5D2_MAX_SUPPORT_HEIGHT;
436 isc->config_dpc = isc_sama5d2_config_dpc;
437 isc->config_csc = isc_sama5d2_config_csc;
438 isc->config_cbc = isc_sama5d2_config_cbc;
439 isc->config_cc = isc_sama5d2_config_cc;
440 isc->config_gam = isc_sama5d2_config_gam;
441 isc->config_rlp = isc_sama5d2_config_rlp;
442 isc->config_ctrls = isc_sama5d2_config_ctrls;
444 isc->adapt_pipeline = isc_sama5d2_adapt_pipeline;
446 isc->offsets.csc = ISC_SAMA5D2_CSC_OFFSET;
447 isc->offsets.cbc = ISC_SAMA5D2_CBC_OFFSET;
448 isc->offsets.sub422 = ISC_SAMA5D2_SUB422_OFFSET;
449 isc->offsets.sub420 = ISC_SAMA5D2_SUB420_OFFSET;
450 isc->offsets.rlp = ISC_SAMA5D2_RLP_OFFSET;
451 isc->offsets.his = ISC_SAMA5D2_HIS_OFFSET;
452 isc->offsets.dma = ISC_SAMA5D2_DMA_OFFSET;
453 isc->offsets.version = ISC_SAMA5D2_VERSION_OFFSET;
454 isc->offsets.his_entry = ISC_SAMA5D2_HIS_ENTRY_OFFSET;
456 isc->controller_formats = sama5d2_controller_formats;
457 isc->controller_formats_size = ARRAY_SIZE(sama5d2_controller_formats);
458 isc->formats_list = sama5d2_formats_list;
459 isc->formats_list_size = ARRAY_SIZE(sama5d2_formats_list);
461 /* sama5d2-isc - 8 bits per beat */
462 isc->dcfg = ISC_DCFG_YMBSIZE_BEATS8 | ISC_DCFG_CMBSIZE_BEATS8;
464 /* sama5d2-isc : ISPCK is required and mandatory */
465 isc->ispck_required = true;
467 ret = isc_pipeline_init(isc);
471 isc->hclock = devm_clk_get(dev, "hclock");
472 if (IS_ERR(isc->hclock)) {
473 ret = PTR_ERR(isc->hclock);
474 dev_err(dev, "failed to get hclock: %d\n", ret);
478 ret = clk_prepare_enable(isc->hclock);
480 dev_err(dev, "failed to enable hclock: %d\n", ret);
484 ret = isc_clk_init(isc);
486 dev_err(dev, "failed to init isc clock: %d\n", ret);
489 ret = v4l2_device_register(dev, &isc->v4l2_dev);
491 dev_err(dev, "unable to register v4l2 device.\n");
495 ret = isc_parse_dt(dev, isc);
497 dev_err(dev, "fail to parse device tree\n");
498 goto unregister_v4l2_device;
501 if (list_empty(&isc->subdev_entities)) {
502 dev_err(dev, "no subdev found\n");
504 goto unregister_v4l2_device;
507 list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
508 struct v4l2_async_subdev *asd;
509 struct fwnode_handle *fwnode =
510 of_fwnode_handle(subdev_entity->epn);
512 v4l2_async_nf_init(&subdev_entity->notifier);
514 asd = v4l2_async_nf_add_fwnode_remote(&subdev_entity->notifier,
516 struct v4l2_async_subdev);
518 of_node_put(subdev_entity->epn);
519 subdev_entity->epn = NULL;
526 subdev_entity->notifier.ops = &isc_async_ops;
528 ret = v4l2_async_nf_register(&isc->v4l2_dev,
529 &subdev_entity->notifier);
531 dev_err(dev, "fail to register async notifier\n");
535 if (video_is_registered(&isc->video_dev))
539 pm_runtime_set_active(dev);
540 pm_runtime_enable(dev);
541 pm_request_idle(dev);
543 isc->ispck = isc->isc_clks[ISC_ISPCK].clk;
545 ret = clk_prepare_enable(isc->ispck);
547 dev_err(dev, "failed to enable ispck: %d\n", ret);
551 /* ispck should be greater or equal to hclock */
552 ret = clk_set_rate(isc->ispck, clk_get_rate(isc->hclock));
554 dev_err(dev, "failed to set ispck rate: %d\n", ret);
558 regmap_read(isc->regmap, ISC_VERSION + isc->offsets.version, &ver);
559 dev_info(dev, "Microchip ISC version %x\n", ver);
564 clk_disable_unprepare(isc->ispck);
567 pm_runtime_disable(dev);
570 isc_subdev_cleanup(isc);
572 unregister_v4l2_device:
573 v4l2_device_unregister(&isc->v4l2_dev);
576 clk_disable_unprepare(isc->hclock);
578 isc_clk_cleanup(isc);
583 static int atmel_isc_remove(struct platform_device *pdev)
585 struct isc_device *isc = platform_get_drvdata(pdev);
587 pm_runtime_disable(&pdev->dev);
589 isc_subdev_cleanup(isc);
591 v4l2_device_unregister(&isc->v4l2_dev);
593 clk_disable_unprepare(isc->ispck);
594 clk_disable_unprepare(isc->hclock);
596 isc_clk_cleanup(isc);
601 static int __maybe_unused isc_runtime_suspend(struct device *dev)
603 struct isc_device *isc = dev_get_drvdata(dev);
605 clk_disable_unprepare(isc->ispck);
606 clk_disable_unprepare(isc->hclock);
611 static int __maybe_unused isc_runtime_resume(struct device *dev)
613 struct isc_device *isc = dev_get_drvdata(dev);
616 ret = clk_prepare_enable(isc->hclock);
620 ret = clk_prepare_enable(isc->ispck);
622 clk_disable_unprepare(isc->hclock);
627 static const struct dev_pm_ops atmel_isc_dev_pm_ops = {
628 SET_RUNTIME_PM_OPS(isc_runtime_suspend, isc_runtime_resume, NULL)
631 #if IS_ENABLED(CONFIG_OF)
632 static const struct of_device_id atmel_isc_of_match[] = {
633 { .compatible = "atmel,sama5d2-isc" },
636 MODULE_DEVICE_TABLE(of, atmel_isc_of_match);
639 static struct platform_driver atmel_isc_driver = {
640 .probe = atmel_isc_probe,
641 .remove = atmel_isc_remove,
643 .name = "atmel-sama5d2-isc",
644 .pm = &atmel_isc_dev_pm_ops,
645 .of_match_table = of_match_ptr(atmel_isc_of_match),
649 module_platform_driver(atmel_isc_driver);
651 MODULE_AUTHOR("Songjun Wu");
652 MODULE_DESCRIPTION("The V4L2 driver for Atmel-ISC");
653 MODULE_LICENSE("GPL v2");