162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Microchip Image Sensor Controller (ISC) driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2016-2019 Microchip Technology, Inc.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Author: Songjun Wu
862306a36Sopenharmony_ci * Author: Eugen Hristev <eugen.hristev@microchip.com>
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * Sensor-->PFE-->WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB-->RLP-->DMA
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci * ISC video pipeline integrates the following submodules:
1462306a36Sopenharmony_ci * PFE: Parallel Front End to sample the camera sensor input stream
1562306a36Sopenharmony_ci *  WB: Programmable white balance in the Bayer domain
1662306a36Sopenharmony_ci * CFA: Color filter array interpolation module
1762306a36Sopenharmony_ci *  CC: Programmable color correction
1862306a36Sopenharmony_ci * GAM: Gamma correction
1962306a36Sopenharmony_ci * CSC: Programmable color space conversion
2062306a36Sopenharmony_ci * CBC: Contrast and Brightness control
2162306a36Sopenharmony_ci * SUB: This module performs YCbCr444 to YCbCr420 chrominance subsampling
2262306a36Sopenharmony_ci * RLP: This module performs rounding, range limiting
2362306a36Sopenharmony_ci *      and packing of the incoming data
2462306a36Sopenharmony_ci */
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#include <linux/clk.h>
2762306a36Sopenharmony_ci#include <linux/clkdev.h>
2862306a36Sopenharmony_ci#include <linux/clk-provider.h>
2962306a36Sopenharmony_ci#include <linux/delay.h>
3062306a36Sopenharmony_ci#include <linux/interrupt.h>
3162306a36Sopenharmony_ci#include <linux/math64.h>
3262306a36Sopenharmony_ci#include <linux/module.h>
3362306a36Sopenharmony_ci#include <linux/of.h>
3462306a36Sopenharmony_ci#include <linux/of_graph.h>
3562306a36Sopenharmony_ci#include <linux/platform_device.h>
3662306a36Sopenharmony_ci#include <linux/pm_runtime.h>
3762306a36Sopenharmony_ci#include <linux/regmap.h>
3862306a36Sopenharmony_ci#include <linux/videodev2.h>
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#include <media/v4l2-ctrls.h>
4162306a36Sopenharmony_ci#include <media/v4l2-device.h>
4262306a36Sopenharmony_ci#include <media/v4l2-event.h>
4362306a36Sopenharmony_ci#include <media/v4l2-image-sizes.h>
4462306a36Sopenharmony_ci#include <media/v4l2-ioctl.h>
4562306a36Sopenharmony_ci#include <media/v4l2-fwnode.h>
4662306a36Sopenharmony_ci#include <media/v4l2-subdev.h>
4762306a36Sopenharmony_ci#include <media/videobuf2-dma-contig.h>
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci#include "microchip-isc-regs.h"
5062306a36Sopenharmony_ci#include "microchip-isc.h"
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#define ISC_SAMA5D2_MAX_SUPPORT_WIDTH   2592
5362306a36Sopenharmony_ci#define ISC_SAMA5D2_MAX_SUPPORT_HEIGHT  1944
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci#define ISC_SAMA5D2_PIPELINE \
5662306a36Sopenharmony_ci	(WB_ENABLE | CFA_ENABLE | CC_ENABLE | GAM_ENABLES | CSC_ENABLE | \
5762306a36Sopenharmony_ci	CBC_ENABLE | SUB422_ENABLE | SUB420_ENABLE)
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci/* This is a list of the formats that the ISC can *output* */
6062306a36Sopenharmony_cistatic const struct isc_format sama5d2_controller_formats[] = {
6162306a36Sopenharmony_ci	{
6262306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_ARGB444,
6362306a36Sopenharmony_ci	}, {
6462306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_ARGB555,
6562306a36Sopenharmony_ci	}, {
6662306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_RGB565,
6762306a36Sopenharmony_ci	}, {
6862306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_ABGR32,
6962306a36Sopenharmony_ci	}, {
7062306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_XBGR32,
7162306a36Sopenharmony_ci	}, {
7262306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_YUV420,
7362306a36Sopenharmony_ci	}, {
7462306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_YUYV,
7562306a36Sopenharmony_ci	}, {
7662306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_YUV422P,
7762306a36Sopenharmony_ci	}, {
7862306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_GREY,
7962306a36Sopenharmony_ci	}, {
8062306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_Y10,
8162306a36Sopenharmony_ci	}, {
8262306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SBGGR8,
8362306a36Sopenharmony_ci		.raw		= true,
8462306a36Sopenharmony_ci	}, {
8562306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SGBRG8,
8662306a36Sopenharmony_ci		.raw		= true,
8762306a36Sopenharmony_ci	}, {
8862306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SGRBG8,
8962306a36Sopenharmony_ci		.raw		= true,
9062306a36Sopenharmony_ci	}, {
9162306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SRGGB8,
9262306a36Sopenharmony_ci		.raw		= true,
9362306a36Sopenharmony_ci	}, {
9462306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SBGGR10,
9562306a36Sopenharmony_ci		.raw		= true,
9662306a36Sopenharmony_ci	}, {
9762306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SGBRG10,
9862306a36Sopenharmony_ci		.raw		= true,
9962306a36Sopenharmony_ci	}, {
10062306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SGRBG10,
10162306a36Sopenharmony_ci		.raw		= true,
10262306a36Sopenharmony_ci	}, {
10362306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SRGGB10,
10462306a36Sopenharmony_ci		.raw		= true,
10562306a36Sopenharmony_ci	}, {
10662306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SBGGR12,
10762306a36Sopenharmony_ci		.raw		= true,
10862306a36Sopenharmony_ci	}, {
10962306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SGBRG12,
11062306a36Sopenharmony_ci		.raw		= true,
11162306a36Sopenharmony_ci	}, {
11262306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SGRBG12,
11362306a36Sopenharmony_ci		.raw		= true,
11462306a36Sopenharmony_ci	}, {
11562306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SRGGB12,
11662306a36Sopenharmony_ci		.raw		= true,
11762306a36Sopenharmony_ci	},
11862306a36Sopenharmony_ci};
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci/* This is a list of formats that the ISC can receive as *input* */
12162306a36Sopenharmony_cistatic struct isc_format sama5d2_formats_list[] = {
12262306a36Sopenharmony_ci	{
12362306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SBGGR8,
12462306a36Sopenharmony_ci		.mbus_code	= MEDIA_BUS_FMT_SBGGR8_1X8,
12562306a36Sopenharmony_ci		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,
12662306a36Sopenharmony_ci		.cfa_baycfg	= ISC_BAY_CFG_BGBG,
12762306a36Sopenharmony_ci	},
12862306a36Sopenharmony_ci	{
12962306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SGBRG8,
13062306a36Sopenharmony_ci		.mbus_code	= MEDIA_BUS_FMT_SGBRG8_1X8,
13162306a36Sopenharmony_ci		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,
13262306a36Sopenharmony_ci		.cfa_baycfg	= ISC_BAY_CFG_GBGB,
13362306a36Sopenharmony_ci	},
13462306a36Sopenharmony_ci	{
13562306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SGRBG8,
13662306a36Sopenharmony_ci		.mbus_code	= MEDIA_BUS_FMT_SGRBG8_1X8,
13762306a36Sopenharmony_ci		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,
13862306a36Sopenharmony_ci		.cfa_baycfg	= ISC_BAY_CFG_GRGR,
13962306a36Sopenharmony_ci	},
14062306a36Sopenharmony_ci	{
14162306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SRGGB8,
14262306a36Sopenharmony_ci		.mbus_code	= MEDIA_BUS_FMT_SRGGB8_1X8,
14362306a36Sopenharmony_ci		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,
14462306a36Sopenharmony_ci		.cfa_baycfg	= ISC_BAY_CFG_RGRG,
14562306a36Sopenharmony_ci	},
14662306a36Sopenharmony_ci	{
14762306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SBGGR10,
14862306a36Sopenharmony_ci		.mbus_code	= MEDIA_BUS_FMT_SBGGR10_1X10,
14962306a36Sopenharmony_ci		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TEN,
15062306a36Sopenharmony_ci		.cfa_baycfg	= ISC_BAY_CFG_RGRG,
15162306a36Sopenharmony_ci	},
15262306a36Sopenharmony_ci	{
15362306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SGBRG10,
15462306a36Sopenharmony_ci		.mbus_code	= MEDIA_BUS_FMT_SGBRG10_1X10,
15562306a36Sopenharmony_ci		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TEN,
15662306a36Sopenharmony_ci		.cfa_baycfg	= ISC_BAY_CFG_GBGB,
15762306a36Sopenharmony_ci	},
15862306a36Sopenharmony_ci	{
15962306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SGRBG10,
16062306a36Sopenharmony_ci		.mbus_code	= MEDIA_BUS_FMT_SGRBG10_1X10,
16162306a36Sopenharmony_ci		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TEN,
16262306a36Sopenharmony_ci		.cfa_baycfg	= ISC_BAY_CFG_GRGR,
16362306a36Sopenharmony_ci	},
16462306a36Sopenharmony_ci	{
16562306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SRGGB10,
16662306a36Sopenharmony_ci		.mbus_code	= MEDIA_BUS_FMT_SRGGB10_1X10,
16762306a36Sopenharmony_ci		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TEN,
16862306a36Sopenharmony_ci		.cfa_baycfg	= ISC_BAY_CFG_RGRG,
16962306a36Sopenharmony_ci	},
17062306a36Sopenharmony_ci	{
17162306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SBGGR12,
17262306a36Sopenharmony_ci		.mbus_code	= MEDIA_BUS_FMT_SBGGR12_1X12,
17362306a36Sopenharmony_ci		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TWELVE,
17462306a36Sopenharmony_ci		.cfa_baycfg	= ISC_BAY_CFG_BGBG,
17562306a36Sopenharmony_ci	},
17662306a36Sopenharmony_ci	{
17762306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SGBRG12,
17862306a36Sopenharmony_ci		.mbus_code	= MEDIA_BUS_FMT_SGBRG12_1X12,
17962306a36Sopenharmony_ci		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TWELVE,
18062306a36Sopenharmony_ci		.cfa_baycfg	= ISC_BAY_CFG_GBGB,
18162306a36Sopenharmony_ci	},
18262306a36Sopenharmony_ci	{
18362306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SGRBG12,
18462306a36Sopenharmony_ci		.mbus_code	= MEDIA_BUS_FMT_SGRBG12_1X12,
18562306a36Sopenharmony_ci		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TWELVE,
18662306a36Sopenharmony_ci		.cfa_baycfg	= ISC_BAY_CFG_GRGR,
18762306a36Sopenharmony_ci	},
18862306a36Sopenharmony_ci	{
18962306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SRGGB12,
19062306a36Sopenharmony_ci		.mbus_code	= MEDIA_BUS_FMT_SRGGB12_1X12,
19162306a36Sopenharmony_ci		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TWELVE,
19262306a36Sopenharmony_ci		.cfa_baycfg	= ISC_BAY_CFG_RGRG,
19362306a36Sopenharmony_ci	},
19462306a36Sopenharmony_ci	{
19562306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_GREY,
19662306a36Sopenharmony_ci		.mbus_code	= MEDIA_BUS_FMT_Y8_1X8,
19762306a36Sopenharmony_ci		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,
19862306a36Sopenharmony_ci	},
19962306a36Sopenharmony_ci	{
20062306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_YUYV,
20162306a36Sopenharmony_ci		.mbus_code	= MEDIA_BUS_FMT_YUYV8_2X8,
20262306a36Sopenharmony_ci		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,
20362306a36Sopenharmony_ci	},
20462306a36Sopenharmony_ci	{
20562306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_RGB565,
20662306a36Sopenharmony_ci		.mbus_code	= MEDIA_BUS_FMT_RGB565_2X8_LE,
20762306a36Sopenharmony_ci		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,
20862306a36Sopenharmony_ci	},
20962306a36Sopenharmony_ci	{
21062306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_Y10,
21162306a36Sopenharmony_ci		.mbus_code	= MEDIA_BUS_FMT_Y10_1X10,
21262306a36Sopenharmony_ci		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TEN,
21362306a36Sopenharmony_ci	},
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci};
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cistatic void isc_sama5d2_config_csc(struct isc_device *isc)
21862306a36Sopenharmony_ci{
21962306a36Sopenharmony_ci	struct regmap *regmap = isc->regmap;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	/* Convert RGB to YUV */
22262306a36Sopenharmony_ci	regmap_write(regmap, ISC_CSC_YR_YG + isc->offsets.csc,
22362306a36Sopenharmony_ci		     0x42 | (0x81 << 16));
22462306a36Sopenharmony_ci	regmap_write(regmap, ISC_CSC_YB_OY + isc->offsets.csc,
22562306a36Sopenharmony_ci		     0x19 | (0x10 << 16));
22662306a36Sopenharmony_ci	regmap_write(regmap, ISC_CSC_CBR_CBG + isc->offsets.csc,
22762306a36Sopenharmony_ci		     0xFDA | (0xFB6 << 16));
22862306a36Sopenharmony_ci	regmap_write(regmap, ISC_CSC_CBB_OCB + isc->offsets.csc,
22962306a36Sopenharmony_ci		     0x70 | (0x80 << 16));
23062306a36Sopenharmony_ci	regmap_write(regmap, ISC_CSC_CRR_CRG + isc->offsets.csc,
23162306a36Sopenharmony_ci		     0x70 | (0xFA2 << 16));
23262306a36Sopenharmony_ci	regmap_write(regmap, ISC_CSC_CRB_OCR + isc->offsets.csc,
23362306a36Sopenharmony_ci		     0xFEE | (0x80 << 16));
23462306a36Sopenharmony_ci}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_cistatic void isc_sama5d2_config_cbc(struct isc_device *isc)
23762306a36Sopenharmony_ci{
23862306a36Sopenharmony_ci	struct regmap *regmap = isc->regmap;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	regmap_write(regmap, ISC_CBC_BRIGHT + isc->offsets.cbc,
24162306a36Sopenharmony_ci		     isc->ctrls.brightness);
24262306a36Sopenharmony_ci	regmap_write(regmap, ISC_CBC_CONTRAST + isc->offsets.cbc,
24362306a36Sopenharmony_ci		     isc->ctrls.contrast);
24462306a36Sopenharmony_ci}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_cistatic void isc_sama5d2_config_cc(struct isc_device *isc)
24762306a36Sopenharmony_ci{
24862306a36Sopenharmony_ci	struct regmap *regmap = isc->regmap;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	/* Configure each register at the neutral fixed point 1.0 or 0.0 */
25162306a36Sopenharmony_ci	regmap_write(regmap, ISC_CC_RR_RG, (1 << 8));
25262306a36Sopenharmony_ci	regmap_write(regmap, ISC_CC_RB_OR, 0);
25362306a36Sopenharmony_ci	regmap_write(regmap, ISC_CC_GR_GG, (1 << 8) << 16);
25462306a36Sopenharmony_ci	regmap_write(regmap, ISC_CC_GB_OG, 0);
25562306a36Sopenharmony_ci	regmap_write(regmap, ISC_CC_BR_BG, 0);
25662306a36Sopenharmony_ci	regmap_write(regmap, ISC_CC_BB_OB, (1 << 8));
25762306a36Sopenharmony_ci}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_cistatic void isc_sama5d2_config_ctrls(struct isc_device *isc,
26062306a36Sopenharmony_ci				     const struct v4l2_ctrl_ops *ops)
26162306a36Sopenharmony_ci{
26262306a36Sopenharmony_ci	struct isc_ctrls *ctrls = &isc->ctrls;
26362306a36Sopenharmony_ci	struct v4l2_ctrl_handler *hdl = &ctrls->handler;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	ctrls->contrast = 256;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -2048, 2047, 1, 256);
26862306a36Sopenharmony_ci}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_cistatic void isc_sama5d2_config_dpc(struct isc_device *isc)
27162306a36Sopenharmony_ci{
27262306a36Sopenharmony_ci	/* This module is not present on sama5d2 pipeline */
27362306a36Sopenharmony_ci}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_cistatic void isc_sama5d2_config_gam(struct isc_device *isc)
27662306a36Sopenharmony_ci{
27762306a36Sopenharmony_ci	/* No specific gamma configuration */
27862306a36Sopenharmony_ci}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_cistatic void isc_sama5d2_config_rlp(struct isc_device *isc)
28162306a36Sopenharmony_ci{
28262306a36Sopenharmony_ci	struct regmap *regmap = isc->regmap;
28362306a36Sopenharmony_ci	u32 rlp_mode = isc->config.rlp_cfg_mode;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	/*
28662306a36Sopenharmony_ci	 * In sama5d2, the YUV planar modes and the YUYV modes are treated
28762306a36Sopenharmony_ci	 * in the same way in RLP register.
28862306a36Sopenharmony_ci	 * Normally, YYCC mode should be Luma(n) - Color B(n) - Color R (n)
28962306a36Sopenharmony_ci	 * and YCYC should be Luma(n + 1) - Color B (n) - Luma (n) - Color R (n)
29062306a36Sopenharmony_ci	 * but in sama5d2, the YCYC mode does not exist, and YYCC must be
29162306a36Sopenharmony_ci	 * selected for both planar and interleaved modes, as in fact
29262306a36Sopenharmony_ci	 * both modes are supported.
29362306a36Sopenharmony_ci	 *
29462306a36Sopenharmony_ci	 * Thus, if the YCYC mode is selected, replace it with the
29562306a36Sopenharmony_ci	 * sama5d2-compliant mode which is YYCC .
29662306a36Sopenharmony_ci	 */
29762306a36Sopenharmony_ci	if ((rlp_mode & ISC_RLP_CFG_MODE_MASK) == ISC_RLP_CFG_MODE_YCYC) {
29862306a36Sopenharmony_ci		rlp_mode &= ~ISC_RLP_CFG_MODE_MASK;
29962306a36Sopenharmony_ci		rlp_mode |= ISC_RLP_CFG_MODE_YYCC;
30062306a36Sopenharmony_ci	}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	regmap_update_bits(regmap, ISC_RLP_CFG + isc->offsets.rlp,
30362306a36Sopenharmony_ci			   ISC_RLP_CFG_MODE_MASK, rlp_mode);
30462306a36Sopenharmony_ci}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_cistatic void isc_sama5d2_adapt_pipeline(struct isc_device *isc)
30762306a36Sopenharmony_ci{
30862306a36Sopenharmony_ci	isc->try_config.bits_pipeline &= ISC_SAMA5D2_PIPELINE;
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci/* Gamma table with gamma 1/2.2 */
31262306a36Sopenharmony_cistatic const u32 isc_sama5d2_gamma_table[][GAMMA_ENTRIES] = {
31362306a36Sopenharmony_ci	/* 0 --> gamma 1/1.8 */
31462306a36Sopenharmony_ci	{      0x65,  0x66002F,  0x950025,  0xBB0020,  0xDB001D,  0xF8001A,
31562306a36Sopenharmony_ci	  0x1130018, 0x12B0017, 0x1420016, 0x1580014, 0x16D0013, 0x1810012,
31662306a36Sopenharmony_ci	  0x1940012, 0x1A60012, 0x1B80011, 0x1C90010, 0x1DA0010, 0x1EA000F,
31762306a36Sopenharmony_ci	  0x1FA000F, 0x209000F, 0x218000F, 0x227000E, 0x235000E, 0x243000E,
31862306a36Sopenharmony_ci	  0x251000E, 0x25F000D, 0x26C000D, 0x279000D, 0x286000D, 0x293000C,
31962306a36Sopenharmony_ci	  0x2A0000C, 0x2AC000C, 0x2B8000C, 0x2C4000C, 0x2D0000B, 0x2DC000B,
32062306a36Sopenharmony_ci	  0x2E7000B, 0x2F3000B, 0x2FE000B, 0x309000B, 0x314000B, 0x31F000A,
32162306a36Sopenharmony_ci	  0x32A000A, 0x334000B, 0x33F000A, 0x349000A, 0x354000A, 0x35E000A,
32262306a36Sopenharmony_ci	  0x368000A, 0x372000A, 0x37C000A, 0x386000A, 0x3900009, 0x399000A,
32362306a36Sopenharmony_ci	  0x3A30009, 0x3AD0009, 0x3B60009, 0x3BF000A, 0x3C90009, 0x3D20009,
32462306a36Sopenharmony_ci	  0x3DB0009, 0x3E40009, 0x3ED0009, 0x3F60009 },
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	/* 1 --> gamma 1/2 */
32762306a36Sopenharmony_ci	{      0x7F,  0x800034,  0xB50028,  0xDE0021, 0x100001E, 0x11E001B,
32862306a36Sopenharmony_ci	  0x1390019, 0x1520017, 0x16A0015, 0x1800014, 0x1940014, 0x1A80013,
32962306a36Sopenharmony_ci	  0x1BB0012, 0x1CD0011, 0x1DF0010, 0x1EF0010, 0x200000F, 0x20F000F,
33062306a36Sopenharmony_ci	  0x21F000E, 0x22D000F, 0x23C000E, 0x24A000E, 0x258000D, 0x265000D,
33162306a36Sopenharmony_ci	  0x273000C, 0x27F000D, 0x28C000C, 0x299000C, 0x2A5000C, 0x2B1000B,
33262306a36Sopenharmony_ci	  0x2BC000C, 0x2C8000B, 0x2D3000C, 0x2DF000B, 0x2EA000A, 0x2F5000A,
33362306a36Sopenharmony_ci	  0x2FF000B, 0x30A000A, 0x314000B, 0x31F000A, 0x329000A, 0x333000A,
33462306a36Sopenharmony_ci	  0x33D0009, 0x3470009, 0x350000A, 0x35A0009, 0x363000A, 0x36D0009,
33562306a36Sopenharmony_ci	  0x3760009, 0x37F0009, 0x3880009, 0x3910009, 0x39A0009, 0x3A30009,
33662306a36Sopenharmony_ci	  0x3AC0008, 0x3B40009, 0x3BD0008, 0x3C60008, 0x3CE0008, 0x3D60009,
33762306a36Sopenharmony_ci	  0x3DF0008, 0x3E70008, 0x3EF0008, 0x3F70008 },
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	/* 2 --> gamma 1/2.2 */
34062306a36Sopenharmony_ci	{      0x99,  0x9B0038,  0xD4002A,  0xFF0023, 0x122001F, 0x141001B,
34162306a36Sopenharmony_ci	  0x15D0019, 0x1760017, 0x18E0015, 0x1A30015, 0x1B80013, 0x1CC0012,
34262306a36Sopenharmony_ci	  0x1DE0011, 0x1F00010, 0x2010010, 0x2110010, 0x221000F, 0x230000F,
34362306a36Sopenharmony_ci	  0x23F000E, 0x24D000E, 0x25B000D, 0x269000C, 0x276000C, 0x283000C,
34462306a36Sopenharmony_ci	  0x28F000C, 0x29B000C, 0x2A7000C, 0x2B3000B, 0x2BF000B, 0x2CA000B,
34562306a36Sopenharmony_ci	  0x2D5000B, 0x2E0000A, 0x2EB000A, 0x2F5000A, 0x2FF000A, 0x30A000A,
34662306a36Sopenharmony_ci	  0x3140009, 0x31E0009, 0x327000A, 0x3310009, 0x33A0009, 0x3440009,
34762306a36Sopenharmony_ci	  0x34D0009, 0x3560009, 0x35F0009, 0x3680008, 0x3710008, 0x3790009,
34862306a36Sopenharmony_ci	  0x3820008, 0x38A0008, 0x3930008, 0x39B0008, 0x3A30008, 0x3AB0008,
34962306a36Sopenharmony_ci	  0x3B30008, 0x3BB0008, 0x3C30008, 0x3CB0007, 0x3D20008, 0x3DA0007,
35062306a36Sopenharmony_ci	  0x3E20007, 0x3E90007, 0x3F00008, 0x3F80007 },
35162306a36Sopenharmony_ci};
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_cistatic int isc_parse_dt(struct device *dev, struct isc_device *isc)
35462306a36Sopenharmony_ci{
35562306a36Sopenharmony_ci	struct device_node *np = dev->of_node;
35662306a36Sopenharmony_ci	struct device_node *epn = NULL;
35762306a36Sopenharmony_ci	struct isc_subdev_entity *subdev_entity;
35862306a36Sopenharmony_ci	unsigned int flags;
35962306a36Sopenharmony_ci	int ret;
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	INIT_LIST_HEAD(&isc->subdev_entities);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	while (1) {
36462306a36Sopenharmony_ci		struct v4l2_fwnode_endpoint v4l2_epn = { .bus_type = 0 };
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci		epn = of_graph_get_next_endpoint(np, epn);
36762306a36Sopenharmony_ci		if (!epn)
36862306a36Sopenharmony_ci			return 0;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci		ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(epn),
37162306a36Sopenharmony_ci						 &v4l2_epn);
37262306a36Sopenharmony_ci		if (ret) {
37362306a36Sopenharmony_ci			ret = -EINVAL;
37462306a36Sopenharmony_ci			dev_err(dev, "Could not parse the endpoint\n");
37562306a36Sopenharmony_ci			break;
37662306a36Sopenharmony_ci		}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci		subdev_entity = devm_kzalloc(dev, sizeof(*subdev_entity),
37962306a36Sopenharmony_ci					     GFP_KERNEL);
38062306a36Sopenharmony_ci		if (!subdev_entity) {
38162306a36Sopenharmony_ci			ret = -ENOMEM;
38262306a36Sopenharmony_ci			break;
38362306a36Sopenharmony_ci		}
38462306a36Sopenharmony_ci		subdev_entity->epn = epn;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci		flags = v4l2_epn.bus.parallel.flags;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci		if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
38962306a36Sopenharmony_ci			subdev_entity->pfe_cfg0 = ISC_PFE_CFG0_HPOL_LOW;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci		if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
39262306a36Sopenharmony_ci			subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_VPOL_LOW;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci		if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
39562306a36Sopenharmony_ci			subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_PPOL_LOW;
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci		if (v4l2_epn.bus_type == V4L2_MBUS_BT656)
39862306a36Sopenharmony_ci			subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_CCIR_CRC |
39962306a36Sopenharmony_ci					ISC_PFE_CFG0_CCIR656;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci		list_add_tail(&subdev_entity->list, &isc->subdev_entities);
40262306a36Sopenharmony_ci	}
40362306a36Sopenharmony_ci	of_node_put(epn);
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	return ret;
40662306a36Sopenharmony_ci}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_cistatic int microchip_isc_probe(struct platform_device *pdev)
40962306a36Sopenharmony_ci{
41062306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
41162306a36Sopenharmony_ci	struct isc_device *isc;
41262306a36Sopenharmony_ci	void __iomem *io_base;
41362306a36Sopenharmony_ci	struct isc_subdev_entity *subdev_entity;
41462306a36Sopenharmony_ci	int irq;
41562306a36Sopenharmony_ci	int ret;
41662306a36Sopenharmony_ci	u32 ver;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	isc = devm_kzalloc(dev, sizeof(*isc), GFP_KERNEL);
41962306a36Sopenharmony_ci	if (!isc)
42062306a36Sopenharmony_ci		return -ENOMEM;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	platform_set_drvdata(pdev, isc);
42362306a36Sopenharmony_ci	isc->dev = dev;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	io_base = devm_platform_ioremap_resource(pdev, 0);
42662306a36Sopenharmony_ci	if (IS_ERR(io_base))
42762306a36Sopenharmony_ci		return PTR_ERR(io_base);
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	isc->regmap = devm_regmap_init_mmio(dev, io_base, &microchip_isc_regmap_config);
43062306a36Sopenharmony_ci	if (IS_ERR(isc->regmap)) {
43162306a36Sopenharmony_ci		ret = PTR_ERR(isc->regmap);
43262306a36Sopenharmony_ci		dev_err(dev, "failed to init register map: %d\n", ret);
43362306a36Sopenharmony_ci		return ret;
43462306a36Sopenharmony_ci	}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
43762306a36Sopenharmony_ci	if (irq < 0)
43862306a36Sopenharmony_ci		return irq;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	ret = devm_request_irq(dev, irq, microchip_isc_interrupt, 0,
44162306a36Sopenharmony_ci			       "microchip-sama5d2-isc", isc);
44262306a36Sopenharmony_ci	if (ret < 0) {
44362306a36Sopenharmony_ci		dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
44462306a36Sopenharmony_ci			irq, ret);
44562306a36Sopenharmony_ci		return ret;
44662306a36Sopenharmony_ci	}
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	isc->gamma_table = isc_sama5d2_gamma_table;
44962306a36Sopenharmony_ci	isc->gamma_max = 2;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	isc->max_width = ISC_SAMA5D2_MAX_SUPPORT_WIDTH;
45262306a36Sopenharmony_ci	isc->max_height = ISC_SAMA5D2_MAX_SUPPORT_HEIGHT;
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	isc->config_dpc = isc_sama5d2_config_dpc;
45562306a36Sopenharmony_ci	isc->config_csc = isc_sama5d2_config_csc;
45662306a36Sopenharmony_ci	isc->config_cbc = isc_sama5d2_config_cbc;
45762306a36Sopenharmony_ci	isc->config_cc = isc_sama5d2_config_cc;
45862306a36Sopenharmony_ci	isc->config_gam = isc_sama5d2_config_gam;
45962306a36Sopenharmony_ci	isc->config_rlp = isc_sama5d2_config_rlp;
46062306a36Sopenharmony_ci	isc->config_ctrls = isc_sama5d2_config_ctrls;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	isc->adapt_pipeline = isc_sama5d2_adapt_pipeline;
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	isc->offsets.csc = ISC_SAMA5D2_CSC_OFFSET;
46562306a36Sopenharmony_ci	isc->offsets.cbc = ISC_SAMA5D2_CBC_OFFSET;
46662306a36Sopenharmony_ci	isc->offsets.sub422 = ISC_SAMA5D2_SUB422_OFFSET;
46762306a36Sopenharmony_ci	isc->offsets.sub420 = ISC_SAMA5D2_SUB420_OFFSET;
46862306a36Sopenharmony_ci	isc->offsets.rlp = ISC_SAMA5D2_RLP_OFFSET;
46962306a36Sopenharmony_ci	isc->offsets.his = ISC_SAMA5D2_HIS_OFFSET;
47062306a36Sopenharmony_ci	isc->offsets.dma = ISC_SAMA5D2_DMA_OFFSET;
47162306a36Sopenharmony_ci	isc->offsets.version = ISC_SAMA5D2_VERSION_OFFSET;
47262306a36Sopenharmony_ci	isc->offsets.his_entry = ISC_SAMA5D2_HIS_ENTRY_OFFSET;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	isc->controller_formats = sama5d2_controller_formats;
47562306a36Sopenharmony_ci	isc->controller_formats_size = ARRAY_SIZE(sama5d2_controller_formats);
47662306a36Sopenharmony_ci	isc->formats_list = sama5d2_formats_list;
47762306a36Sopenharmony_ci	isc->formats_list_size = ARRAY_SIZE(sama5d2_formats_list);
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	/* sama5d2-isc - 8 bits per beat */
48062306a36Sopenharmony_ci	isc->dcfg = ISC_DCFG_YMBSIZE_BEATS8 | ISC_DCFG_CMBSIZE_BEATS8;
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	/* sama5d2-isc : ISPCK is required and mandatory */
48362306a36Sopenharmony_ci	isc->ispck_required = true;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	ret = microchip_isc_pipeline_init(isc);
48662306a36Sopenharmony_ci	if (ret)
48762306a36Sopenharmony_ci		return ret;
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	isc->hclock = devm_clk_get(dev, "hclock");
49062306a36Sopenharmony_ci	if (IS_ERR(isc->hclock)) {
49162306a36Sopenharmony_ci		ret = PTR_ERR(isc->hclock);
49262306a36Sopenharmony_ci		dev_err(dev, "failed to get hclock: %d\n", ret);
49362306a36Sopenharmony_ci		return ret;
49462306a36Sopenharmony_ci	}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	ret = clk_prepare_enable(isc->hclock);
49762306a36Sopenharmony_ci	if (ret) {
49862306a36Sopenharmony_ci		dev_err(dev, "failed to enable hclock: %d\n", ret);
49962306a36Sopenharmony_ci		return ret;
50062306a36Sopenharmony_ci	}
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	ret = microchip_isc_clk_init(isc);
50362306a36Sopenharmony_ci	if (ret) {
50462306a36Sopenharmony_ci		dev_err(dev, "failed to init isc clock: %d\n", ret);
50562306a36Sopenharmony_ci		goto unprepare_hclk;
50662306a36Sopenharmony_ci	}
50762306a36Sopenharmony_ci	ret = v4l2_device_register(dev, &isc->v4l2_dev);
50862306a36Sopenharmony_ci	if (ret) {
50962306a36Sopenharmony_ci		dev_err(dev, "unable to register v4l2 device.\n");
51062306a36Sopenharmony_ci		goto unprepare_clk;
51162306a36Sopenharmony_ci	}
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	ret = isc_parse_dt(dev, isc);
51462306a36Sopenharmony_ci	if (ret) {
51562306a36Sopenharmony_ci		dev_err(dev, "fail to parse device tree\n");
51662306a36Sopenharmony_ci		goto unregister_v4l2_device;
51762306a36Sopenharmony_ci	}
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	if (list_empty(&isc->subdev_entities)) {
52062306a36Sopenharmony_ci		dev_err(dev, "no subdev found\n");
52162306a36Sopenharmony_ci		ret = -ENODEV;
52262306a36Sopenharmony_ci		goto unregister_v4l2_device;
52362306a36Sopenharmony_ci	}
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
52662306a36Sopenharmony_ci		struct v4l2_async_connection *asd;
52762306a36Sopenharmony_ci		struct fwnode_handle *fwnode =
52862306a36Sopenharmony_ci			of_fwnode_handle(subdev_entity->epn);
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci		v4l2_async_nf_init(&subdev_entity->notifier, &isc->v4l2_dev);
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci		asd = v4l2_async_nf_add_fwnode_remote(&subdev_entity->notifier,
53362306a36Sopenharmony_ci						      fwnode,
53462306a36Sopenharmony_ci						      struct v4l2_async_connection);
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci		of_node_put(subdev_entity->epn);
53762306a36Sopenharmony_ci		subdev_entity->epn = NULL;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci		if (IS_ERR(asd)) {
54062306a36Sopenharmony_ci			ret = PTR_ERR(asd);
54162306a36Sopenharmony_ci			goto cleanup_subdev;
54262306a36Sopenharmony_ci		}
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci		subdev_entity->notifier.ops = &microchip_isc_async_ops;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci		ret = v4l2_async_nf_register(&subdev_entity->notifier);
54762306a36Sopenharmony_ci		if (ret) {
54862306a36Sopenharmony_ci			dev_err(dev, "fail to register async notifier\n");
54962306a36Sopenharmony_ci			goto cleanup_subdev;
55062306a36Sopenharmony_ci		}
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci		if (video_is_registered(&isc->video_dev))
55362306a36Sopenharmony_ci			break;
55462306a36Sopenharmony_ci	}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	regmap_read(isc->regmap, ISC_VERSION + isc->offsets.version, &ver);
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	ret = isc_mc_init(isc, ver);
55962306a36Sopenharmony_ci	if (ret < 0)
56062306a36Sopenharmony_ci		goto isc_probe_mc_init_err;
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	pm_runtime_set_active(dev);
56362306a36Sopenharmony_ci	pm_runtime_enable(dev);
56462306a36Sopenharmony_ci	pm_request_idle(dev);
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	isc->ispck = isc->isc_clks[ISC_ISPCK].clk;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	ret = clk_prepare_enable(isc->ispck);
56962306a36Sopenharmony_ci	if (ret) {
57062306a36Sopenharmony_ci		dev_err(dev, "failed to enable ispck: %d\n", ret);
57162306a36Sopenharmony_ci		goto disable_pm;
57262306a36Sopenharmony_ci	}
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	/* ispck should be greater or equal to hclock */
57562306a36Sopenharmony_ci	ret = clk_set_rate(isc->ispck, clk_get_rate(isc->hclock));
57662306a36Sopenharmony_ci	if (ret) {
57762306a36Sopenharmony_ci		dev_err(dev, "failed to set ispck rate: %d\n", ret);
57862306a36Sopenharmony_ci		goto unprepare_clk;
57962306a36Sopenharmony_ci	}
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	dev_info(dev, "Microchip ISC version %x\n", ver);
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	return 0;
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ciunprepare_clk:
58662306a36Sopenharmony_ci	clk_disable_unprepare(isc->ispck);
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_cidisable_pm:
58962306a36Sopenharmony_ci	pm_runtime_disable(dev);
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ciisc_probe_mc_init_err:
59262306a36Sopenharmony_ci	isc_mc_cleanup(isc);
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_cicleanup_subdev:
59562306a36Sopenharmony_ci	microchip_isc_subdev_cleanup(isc);
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ciunregister_v4l2_device:
59862306a36Sopenharmony_ci	v4l2_device_unregister(&isc->v4l2_dev);
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ciunprepare_hclk:
60162306a36Sopenharmony_ci	clk_disable_unprepare(isc->hclock);
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	microchip_isc_clk_cleanup(isc);
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	return ret;
60662306a36Sopenharmony_ci}
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_cistatic void microchip_isc_remove(struct platform_device *pdev)
60962306a36Sopenharmony_ci{
61062306a36Sopenharmony_ci	struct isc_device *isc = platform_get_drvdata(pdev);
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	isc_mc_cleanup(isc);
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	microchip_isc_subdev_cleanup(isc);
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	v4l2_device_unregister(&isc->v4l2_dev);
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	clk_disable_unprepare(isc->ispck);
62162306a36Sopenharmony_ci	clk_disable_unprepare(isc->hclock);
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	microchip_isc_clk_cleanup(isc);
62462306a36Sopenharmony_ci}
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_cistatic int __maybe_unused isc_runtime_suspend(struct device *dev)
62762306a36Sopenharmony_ci{
62862306a36Sopenharmony_ci	struct isc_device *isc = dev_get_drvdata(dev);
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	clk_disable_unprepare(isc->ispck);
63162306a36Sopenharmony_ci	clk_disable_unprepare(isc->hclock);
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	return 0;
63462306a36Sopenharmony_ci}
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_cistatic int __maybe_unused isc_runtime_resume(struct device *dev)
63762306a36Sopenharmony_ci{
63862306a36Sopenharmony_ci	struct isc_device *isc = dev_get_drvdata(dev);
63962306a36Sopenharmony_ci	int ret;
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	ret = clk_prepare_enable(isc->hclock);
64262306a36Sopenharmony_ci	if (ret)
64362306a36Sopenharmony_ci		return ret;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	ret = clk_prepare_enable(isc->ispck);
64662306a36Sopenharmony_ci	if (ret)
64762306a36Sopenharmony_ci		clk_disable_unprepare(isc->hclock);
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	return ret;
65062306a36Sopenharmony_ci}
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_cistatic const struct dev_pm_ops microchip_isc_dev_pm_ops = {
65362306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(isc_runtime_suspend, isc_runtime_resume, NULL)
65462306a36Sopenharmony_ci};
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_OF)
65762306a36Sopenharmony_cistatic const struct of_device_id microchip_isc_of_match[] = {
65862306a36Sopenharmony_ci	{ .compatible = "atmel,sama5d2-isc" },
65962306a36Sopenharmony_ci	{ }
66062306a36Sopenharmony_ci};
66162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, microchip_isc_of_match);
66262306a36Sopenharmony_ci#endif
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_cistatic struct platform_driver microchip_isc_driver = {
66562306a36Sopenharmony_ci	.probe	= microchip_isc_probe,
66662306a36Sopenharmony_ci	.remove_new = microchip_isc_remove,
66762306a36Sopenharmony_ci	.driver	= {
66862306a36Sopenharmony_ci		.name		= "microchip-sama5d2-isc",
66962306a36Sopenharmony_ci		.pm		= &microchip_isc_dev_pm_ops,
67062306a36Sopenharmony_ci		.of_match_table = of_match_ptr(microchip_isc_of_match),
67162306a36Sopenharmony_ci	},
67262306a36Sopenharmony_ci};
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_cimodule_platform_driver(microchip_isc_driver);
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ciMODULE_AUTHOR("Songjun Wu");
67762306a36Sopenharmony_ciMODULE_DESCRIPTION("The V4L2 driver for Microchip-ISC");
67862306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
679