xref: /openbmc/linux/drivers/media/platform/microchip/microchip-sama5d2-isc.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
191b4e487SEugen Hristev // SPDX-License-Identifier: GPL-2.0
291b4e487SEugen Hristev /*
391b4e487SEugen Hristev  * Microchip Image Sensor Controller (ISC) driver
491b4e487SEugen Hristev  *
591b4e487SEugen Hristev  * Copyright (C) 2016-2019 Microchip Technology, Inc.
691b4e487SEugen Hristev  *
791b4e487SEugen Hristev  * Author: Songjun Wu
891b4e487SEugen Hristev  * Author: Eugen Hristev <eugen.hristev@microchip.com>
991b4e487SEugen Hristev  *
1091b4e487SEugen Hristev  *
1191b4e487SEugen Hristev  * Sensor-->PFE-->WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB-->RLP-->DMA
1291b4e487SEugen Hristev  *
1391b4e487SEugen Hristev  * ISC video pipeline integrates the following submodules:
1491b4e487SEugen Hristev  * PFE: Parallel Front End to sample the camera sensor input stream
1591b4e487SEugen Hristev  *  WB: Programmable white balance in the Bayer domain
1691b4e487SEugen Hristev  * CFA: Color filter array interpolation module
1791b4e487SEugen Hristev  *  CC: Programmable color correction
1891b4e487SEugen Hristev  * GAM: Gamma correction
1991b4e487SEugen Hristev  * CSC: Programmable color space conversion
2091b4e487SEugen Hristev  * CBC: Contrast and Brightness control
2191b4e487SEugen Hristev  * SUB: This module performs YCbCr444 to YCbCr420 chrominance subsampling
2291b4e487SEugen Hristev  * RLP: This module performs rounding, range limiting
2391b4e487SEugen Hristev  *      and packing of the incoming data
2491b4e487SEugen Hristev  */
2591b4e487SEugen Hristev 
2691b4e487SEugen Hristev #include <linux/clk.h>
2791b4e487SEugen Hristev #include <linux/clkdev.h>
2891b4e487SEugen Hristev #include <linux/clk-provider.h>
2991b4e487SEugen Hristev #include <linux/delay.h>
3091b4e487SEugen Hristev #include <linux/interrupt.h>
3191b4e487SEugen Hristev #include <linux/math64.h>
3291b4e487SEugen Hristev #include <linux/module.h>
3391b4e487SEugen Hristev #include <linux/of.h>
3491b4e487SEugen Hristev #include <linux/of_graph.h>
3591b4e487SEugen Hristev #include <linux/platform_device.h>
3691b4e487SEugen Hristev #include <linux/pm_runtime.h>
3791b4e487SEugen Hristev #include <linux/regmap.h>
3891b4e487SEugen Hristev #include <linux/videodev2.h>
3991b4e487SEugen Hristev 
4091b4e487SEugen Hristev #include <media/v4l2-ctrls.h>
4191b4e487SEugen Hristev #include <media/v4l2-device.h>
4291b4e487SEugen Hristev #include <media/v4l2-event.h>
4391b4e487SEugen Hristev #include <media/v4l2-image-sizes.h>
4491b4e487SEugen Hristev #include <media/v4l2-ioctl.h>
4591b4e487SEugen Hristev #include <media/v4l2-fwnode.h>
4691b4e487SEugen Hristev #include <media/v4l2-subdev.h>
4791b4e487SEugen Hristev #include <media/videobuf2-dma-contig.h>
4891b4e487SEugen Hristev 
4991b4e487SEugen Hristev #include "microchip-isc-regs.h"
5091b4e487SEugen Hristev #include "microchip-isc.h"
5191b4e487SEugen Hristev 
5291b4e487SEugen Hristev #define ISC_SAMA5D2_MAX_SUPPORT_WIDTH   2592
5391b4e487SEugen Hristev #define ISC_SAMA5D2_MAX_SUPPORT_HEIGHT  1944
5491b4e487SEugen Hristev 
5591b4e487SEugen Hristev #define ISC_SAMA5D2_PIPELINE \
5691b4e487SEugen Hristev 	(WB_ENABLE | CFA_ENABLE | CC_ENABLE | GAM_ENABLES | CSC_ENABLE | \
5791b4e487SEugen Hristev 	CBC_ENABLE | SUB422_ENABLE | SUB420_ENABLE)
5891b4e487SEugen Hristev 
5991b4e487SEugen Hristev /* This is a list of the formats that the ISC can *output* */
6091b4e487SEugen Hristev static const struct isc_format sama5d2_controller_formats[] = {
6191b4e487SEugen Hristev 	{
6291b4e487SEugen Hristev 		.fourcc		= V4L2_PIX_FMT_ARGB444,
6391b4e487SEugen Hristev 	}, {
6491b4e487SEugen Hristev 		.fourcc		= V4L2_PIX_FMT_ARGB555,
6591b4e487SEugen Hristev 	}, {
6691b4e487SEugen Hristev 		.fourcc		= V4L2_PIX_FMT_RGB565,
6791b4e487SEugen Hristev 	}, {
6891b4e487SEugen Hristev 		.fourcc		= V4L2_PIX_FMT_ABGR32,
6991b4e487SEugen Hristev 	}, {
7091b4e487SEugen Hristev 		.fourcc		= V4L2_PIX_FMT_XBGR32,
7191b4e487SEugen Hristev 	}, {
7291b4e487SEugen Hristev 		.fourcc		= V4L2_PIX_FMT_YUV420,
7391b4e487SEugen Hristev 	}, {
7491b4e487SEugen Hristev 		.fourcc		= V4L2_PIX_FMT_YUYV,
7591b4e487SEugen Hristev 	}, {
7691b4e487SEugen Hristev 		.fourcc		= V4L2_PIX_FMT_YUV422P,
7791b4e487SEugen Hristev 	}, {
7891b4e487SEugen Hristev 		.fourcc		= V4L2_PIX_FMT_GREY,
7991b4e487SEugen Hristev 	}, {
8091b4e487SEugen Hristev 		.fourcc		= V4L2_PIX_FMT_Y10,
8191b4e487SEugen Hristev 	}, {
8291b4e487SEugen Hristev 		.fourcc		= V4L2_PIX_FMT_SBGGR8,
8378ba0d79SEugen Hristev 		.raw		= true,
8491b4e487SEugen Hristev 	}, {
8591b4e487SEugen Hristev 		.fourcc		= V4L2_PIX_FMT_SGBRG8,
8678ba0d79SEugen Hristev 		.raw		= true,
8791b4e487SEugen Hristev 	}, {
8891b4e487SEugen Hristev 		.fourcc		= V4L2_PIX_FMT_SGRBG8,
8978ba0d79SEugen Hristev 		.raw		= true,
9091b4e487SEugen Hristev 	}, {
9191b4e487SEugen Hristev 		.fourcc		= V4L2_PIX_FMT_SRGGB8,
9278ba0d79SEugen Hristev 		.raw		= true,
9391b4e487SEugen Hristev 	}, {
9491b4e487SEugen Hristev 		.fourcc		= V4L2_PIX_FMT_SBGGR10,
9578ba0d79SEugen Hristev 		.raw		= true,
9691b4e487SEugen Hristev 	}, {
9791b4e487SEugen Hristev 		.fourcc		= V4L2_PIX_FMT_SGBRG10,
9878ba0d79SEugen Hristev 		.raw		= true,
9991b4e487SEugen Hristev 	}, {
10091b4e487SEugen Hristev 		.fourcc		= V4L2_PIX_FMT_SGRBG10,
10178ba0d79SEugen Hristev 		.raw		= true,
10291b4e487SEugen Hristev 	}, {
10391b4e487SEugen Hristev 		.fourcc		= V4L2_PIX_FMT_SRGGB10,
10478ba0d79SEugen Hristev 		.raw		= true,
10578ba0d79SEugen Hristev 	}, {
10678ba0d79SEugen Hristev 		.fourcc		= V4L2_PIX_FMT_SBGGR12,
10778ba0d79SEugen Hristev 		.raw		= true,
10878ba0d79SEugen Hristev 	}, {
10978ba0d79SEugen Hristev 		.fourcc		= V4L2_PIX_FMT_SGBRG12,
11078ba0d79SEugen Hristev 		.raw		= true,
11178ba0d79SEugen Hristev 	}, {
11278ba0d79SEugen Hristev 		.fourcc		= V4L2_PIX_FMT_SGRBG12,
11378ba0d79SEugen Hristev 		.raw		= true,
11478ba0d79SEugen Hristev 	}, {
11578ba0d79SEugen Hristev 		.fourcc		= V4L2_PIX_FMT_SRGGB12,
11678ba0d79SEugen Hristev 		.raw		= true,
11791b4e487SEugen Hristev 	},
11891b4e487SEugen Hristev };
11991b4e487SEugen Hristev 
12091b4e487SEugen Hristev /* This is a list of formats that the ISC can receive as *input* */
12191b4e487SEugen Hristev static struct isc_format sama5d2_formats_list[] = {
12291b4e487SEugen Hristev 	{
12391b4e487SEugen Hristev 		.fourcc		= V4L2_PIX_FMT_SBGGR8,
12491b4e487SEugen Hristev 		.mbus_code	= MEDIA_BUS_FMT_SBGGR8_1X8,
12591b4e487SEugen Hristev 		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,
12691b4e487SEugen Hristev 		.cfa_baycfg	= ISC_BAY_CFG_BGBG,
12791b4e487SEugen Hristev 	},
12891b4e487SEugen Hristev 	{
12991b4e487SEugen Hristev 		.fourcc		= V4L2_PIX_FMT_SGBRG8,
13091b4e487SEugen Hristev 		.mbus_code	= MEDIA_BUS_FMT_SGBRG8_1X8,
13191b4e487SEugen Hristev 		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,
13291b4e487SEugen Hristev 		.cfa_baycfg	= ISC_BAY_CFG_GBGB,
13391b4e487SEugen Hristev 	},
13491b4e487SEugen Hristev 	{
13591b4e487SEugen Hristev 		.fourcc		= V4L2_PIX_FMT_SGRBG8,
13691b4e487SEugen Hristev 		.mbus_code	= MEDIA_BUS_FMT_SGRBG8_1X8,
13791b4e487SEugen Hristev 		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,
13891b4e487SEugen Hristev 		.cfa_baycfg	= ISC_BAY_CFG_GRGR,
13991b4e487SEugen Hristev 	},
14091b4e487SEugen Hristev 	{
14191b4e487SEugen Hristev 		.fourcc		= V4L2_PIX_FMT_SRGGB8,
14291b4e487SEugen Hristev 		.mbus_code	= MEDIA_BUS_FMT_SRGGB8_1X8,
14391b4e487SEugen Hristev 		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,
14491b4e487SEugen Hristev 		.cfa_baycfg	= ISC_BAY_CFG_RGRG,
14591b4e487SEugen Hristev 	},
14691b4e487SEugen Hristev 	{
14791b4e487SEugen Hristev 		.fourcc		= V4L2_PIX_FMT_SBGGR10,
14891b4e487SEugen Hristev 		.mbus_code	= MEDIA_BUS_FMT_SBGGR10_1X10,
14991b4e487SEugen Hristev 		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TEN,
15091b4e487SEugen Hristev 		.cfa_baycfg	= ISC_BAY_CFG_RGRG,
15191b4e487SEugen Hristev 	},
15291b4e487SEugen Hristev 	{
15391b4e487SEugen Hristev 		.fourcc		= V4L2_PIX_FMT_SGBRG10,
15491b4e487SEugen Hristev 		.mbus_code	= MEDIA_BUS_FMT_SGBRG10_1X10,
15591b4e487SEugen Hristev 		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TEN,
15691b4e487SEugen Hristev 		.cfa_baycfg	= ISC_BAY_CFG_GBGB,
15791b4e487SEugen Hristev 	},
15891b4e487SEugen Hristev 	{
15991b4e487SEugen Hristev 		.fourcc		= V4L2_PIX_FMT_SGRBG10,
16091b4e487SEugen Hristev 		.mbus_code	= MEDIA_BUS_FMT_SGRBG10_1X10,
16191b4e487SEugen Hristev 		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TEN,
16291b4e487SEugen Hristev 		.cfa_baycfg	= ISC_BAY_CFG_GRGR,
16391b4e487SEugen Hristev 	},
16491b4e487SEugen Hristev 	{
16591b4e487SEugen Hristev 		.fourcc		= V4L2_PIX_FMT_SRGGB10,
16691b4e487SEugen Hristev 		.mbus_code	= MEDIA_BUS_FMT_SRGGB10_1X10,
16791b4e487SEugen Hristev 		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TEN,
16891b4e487SEugen Hristev 		.cfa_baycfg	= ISC_BAY_CFG_RGRG,
16991b4e487SEugen Hristev 	},
17091b4e487SEugen Hristev 	{
17191b4e487SEugen Hristev 		.fourcc		= V4L2_PIX_FMT_SBGGR12,
17291b4e487SEugen Hristev 		.mbus_code	= MEDIA_BUS_FMT_SBGGR12_1X12,
17391b4e487SEugen Hristev 		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TWELVE,
17491b4e487SEugen Hristev 		.cfa_baycfg	= ISC_BAY_CFG_BGBG,
17591b4e487SEugen Hristev 	},
17691b4e487SEugen Hristev 	{
17791b4e487SEugen Hristev 		.fourcc		= V4L2_PIX_FMT_SGBRG12,
17891b4e487SEugen Hristev 		.mbus_code	= MEDIA_BUS_FMT_SGBRG12_1X12,
17991b4e487SEugen Hristev 		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TWELVE,
18091b4e487SEugen Hristev 		.cfa_baycfg	= ISC_BAY_CFG_GBGB,
18191b4e487SEugen Hristev 	},
18291b4e487SEugen Hristev 	{
18391b4e487SEugen Hristev 		.fourcc		= V4L2_PIX_FMT_SGRBG12,
18491b4e487SEugen Hristev 		.mbus_code	= MEDIA_BUS_FMT_SGRBG12_1X12,
18591b4e487SEugen Hristev 		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TWELVE,
18691b4e487SEugen Hristev 		.cfa_baycfg	= ISC_BAY_CFG_GRGR,
18791b4e487SEugen Hristev 	},
18891b4e487SEugen Hristev 	{
18991b4e487SEugen Hristev 		.fourcc		= V4L2_PIX_FMT_SRGGB12,
19091b4e487SEugen Hristev 		.mbus_code	= MEDIA_BUS_FMT_SRGGB12_1X12,
19191b4e487SEugen Hristev 		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TWELVE,
19291b4e487SEugen Hristev 		.cfa_baycfg	= ISC_BAY_CFG_RGRG,
19391b4e487SEugen Hristev 	},
19491b4e487SEugen Hristev 	{
19591b4e487SEugen Hristev 		.fourcc		= V4L2_PIX_FMT_GREY,
19691b4e487SEugen Hristev 		.mbus_code	= MEDIA_BUS_FMT_Y8_1X8,
19791b4e487SEugen Hristev 		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,
19891b4e487SEugen Hristev 	},
19991b4e487SEugen Hristev 	{
20091b4e487SEugen Hristev 		.fourcc		= V4L2_PIX_FMT_YUYV,
20191b4e487SEugen Hristev 		.mbus_code	= MEDIA_BUS_FMT_YUYV8_2X8,
20291b4e487SEugen Hristev 		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,
20391b4e487SEugen Hristev 	},
20491b4e487SEugen Hristev 	{
20591b4e487SEugen Hristev 		.fourcc		= V4L2_PIX_FMT_RGB565,
20691b4e487SEugen Hristev 		.mbus_code	= MEDIA_BUS_FMT_RGB565_2X8_LE,
20791b4e487SEugen Hristev 		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,
20891b4e487SEugen Hristev 	},
20991b4e487SEugen Hristev 	{
21091b4e487SEugen Hristev 		.fourcc		= V4L2_PIX_FMT_Y10,
21191b4e487SEugen Hristev 		.mbus_code	= MEDIA_BUS_FMT_Y10_1X10,
21291b4e487SEugen Hristev 		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TEN,
21391b4e487SEugen Hristev 	},
21491b4e487SEugen Hristev 
21591b4e487SEugen Hristev };
21691b4e487SEugen Hristev 
isc_sama5d2_config_csc(struct isc_device * isc)21791b4e487SEugen Hristev static void isc_sama5d2_config_csc(struct isc_device *isc)
21891b4e487SEugen Hristev {
21991b4e487SEugen Hristev 	struct regmap *regmap = isc->regmap;
22091b4e487SEugen Hristev 
22191b4e487SEugen Hristev 	/* Convert RGB to YUV */
22291b4e487SEugen Hristev 	regmap_write(regmap, ISC_CSC_YR_YG + isc->offsets.csc,
22391b4e487SEugen Hristev 		     0x42 | (0x81 << 16));
22491b4e487SEugen Hristev 	regmap_write(regmap, ISC_CSC_YB_OY + isc->offsets.csc,
22591b4e487SEugen Hristev 		     0x19 | (0x10 << 16));
22691b4e487SEugen Hristev 	regmap_write(regmap, ISC_CSC_CBR_CBG + isc->offsets.csc,
22791b4e487SEugen Hristev 		     0xFDA | (0xFB6 << 16));
22891b4e487SEugen Hristev 	regmap_write(regmap, ISC_CSC_CBB_OCB + isc->offsets.csc,
22991b4e487SEugen Hristev 		     0x70 | (0x80 << 16));
23091b4e487SEugen Hristev 	regmap_write(regmap, ISC_CSC_CRR_CRG + isc->offsets.csc,
23191b4e487SEugen Hristev 		     0x70 | (0xFA2 << 16));
23291b4e487SEugen Hristev 	regmap_write(regmap, ISC_CSC_CRB_OCR + isc->offsets.csc,
23391b4e487SEugen Hristev 		     0xFEE | (0x80 << 16));
23491b4e487SEugen Hristev }
23591b4e487SEugen Hristev 
isc_sama5d2_config_cbc(struct isc_device * isc)23691b4e487SEugen Hristev static void isc_sama5d2_config_cbc(struct isc_device *isc)
23791b4e487SEugen Hristev {
23891b4e487SEugen Hristev 	struct regmap *regmap = isc->regmap;
23991b4e487SEugen Hristev 
24091b4e487SEugen Hristev 	regmap_write(regmap, ISC_CBC_BRIGHT + isc->offsets.cbc,
24191b4e487SEugen Hristev 		     isc->ctrls.brightness);
24291b4e487SEugen Hristev 	regmap_write(regmap, ISC_CBC_CONTRAST + isc->offsets.cbc,
24391b4e487SEugen Hristev 		     isc->ctrls.contrast);
24491b4e487SEugen Hristev }
24591b4e487SEugen Hristev 
isc_sama5d2_config_cc(struct isc_device * isc)24691b4e487SEugen Hristev static void isc_sama5d2_config_cc(struct isc_device *isc)
24791b4e487SEugen Hristev {
24891b4e487SEugen Hristev 	struct regmap *regmap = isc->regmap;
24991b4e487SEugen Hristev 
25091b4e487SEugen Hristev 	/* Configure each register at the neutral fixed point 1.0 or 0.0 */
25191b4e487SEugen Hristev 	regmap_write(regmap, ISC_CC_RR_RG, (1 << 8));
25291b4e487SEugen Hristev 	regmap_write(regmap, ISC_CC_RB_OR, 0);
25391b4e487SEugen Hristev 	regmap_write(regmap, ISC_CC_GR_GG, (1 << 8) << 16);
25491b4e487SEugen Hristev 	regmap_write(regmap, ISC_CC_GB_OG, 0);
25591b4e487SEugen Hristev 	regmap_write(regmap, ISC_CC_BR_BG, 0);
25691b4e487SEugen Hristev 	regmap_write(regmap, ISC_CC_BB_OB, (1 << 8));
25791b4e487SEugen Hristev }
25891b4e487SEugen Hristev 
isc_sama5d2_config_ctrls(struct isc_device * isc,const struct v4l2_ctrl_ops * ops)25991b4e487SEugen Hristev static void isc_sama5d2_config_ctrls(struct isc_device *isc,
26091b4e487SEugen Hristev 				     const struct v4l2_ctrl_ops *ops)
26191b4e487SEugen Hristev {
26291b4e487SEugen Hristev 	struct isc_ctrls *ctrls = &isc->ctrls;
26391b4e487SEugen Hristev 	struct v4l2_ctrl_handler *hdl = &ctrls->handler;
26491b4e487SEugen Hristev 
26591b4e487SEugen Hristev 	ctrls->contrast = 256;
26691b4e487SEugen Hristev 
26791b4e487SEugen Hristev 	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -2048, 2047, 1, 256);
26891b4e487SEugen Hristev }
26991b4e487SEugen Hristev 
isc_sama5d2_config_dpc(struct isc_device * isc)27091b4e487SEugen Hristev static void isc_sama5d2_config_dpc(struct isc_device *isc)
27191b4e487SEugen Hristev {
27291b4e487SEugen Hristev 	/* This module is not present on sama5d2 pipeline */
27391b4e487SEugen Hristev }
27491b4e487SEugen Hristev 
isc_sama5d2_config_gam(struct isc_device * isc)27591b4e487SEugen Hristev static void isc_sama5d2_config_gam(struct isc_device *isc)
27691b4e487SEugen Hristev {
27791b4e487SEugen Hristev 	/* No specific gamma configuration */
27891b4e487SEugen Hristev }
27991b4e487SEugen Hristev 
isc_sama5d2_config_rlp(struct isc_device * isc)28091b4e487SEugen Hristev static void isc_sama5d2_config_rlp(struct isc_device *isc)
28191b4e487SEugen Hristev {
28291b4e487SEugen Hristev 	struct regmap *regmap = isc->regmap;
28391b4e487SEugen Hristev 	u32 rlp_mode = isc->config.rlp_cfg_mode;
28491b4e487SEugen Hristev 
28591b4e487SEugen Hristev 	/*
28691b4e487SEugen Hristev 	 * In sama5d2, the YUV planar modes and the YUYV modes are treated
28791b4e487SEugen Hristev 	 * in the same way in RLP register.
28891b4e487SEugen Hristev 	 * Normally, YYCC mode should be Luma(n) - Color B(n) - Color R (n)
28991b4e487SEugen Hristev 	 * and YCYC should be Luma(n + 1) - Color B (n) - Luma (n) - Color R (n)
29091b4e487SEugen Hristev 	 * but in sama5d2, the YCYC mode does not exist, and YYCC must be
29191b4e487SEugen Hristev 	 * selected for both planar and interleaved modes, as in fact
29291b4e487SEugen Hristev 	 * both modes are supported.
29391b4e487SEugen Hristev 	 *
29491b4e487SEugen Hristev 	 * Thus, if the YCYC mode is selected, replace it with the
29591b4e487SEugen Hristev 	 * sama5d2-compliant mode which is YYCC .
29691b4e487SEugen Hristev 	 */
29791b4e487SEugen Hristev 	if ((rlp_mode & ISC_RLP_CFG_MODE_MASK) == ISC_RLP_CFG_MODE_YCYC) {
29891b4e487SEugen Hristev 		rlp_mode &= ~ISC_RLP_CFG_MODE_MASK;
29991b4e487SEugen Hristev 		rlp_mode |= ISC_RLP_CFG_MODE_YYCC;
30091b4e487SEugen Hristev 	}
30191b4e487SEugen Hristev 
30291b4e487SEugen Hristev 	regmap_update_bits(regmap, ISC_RLP_CFG + isc->offsets.rlp,
30391b4e487SEugen Hristev 			   ISC_RLP_CFG_MODE_MASK, rlp_mode);
30491b4e487SEugen Hristev }
30591b4e487SEugen Hristev 
isc_sama5d2_adapt_pipeline(struct isc_device * isc)30691b4e487SEugen Hristev static void isc_sama5d2_adapt_pipeline(struct isc_device *isc)
30791b4e487SEugen Hristev {
30891b4e487SEugen Hristev 	isc->try_config.bits_pipeline &= ISC_SAMA5D2_PIPELINE;
30991b4e487SEugen Hristev }
31091b4e487SEugen Hristev 
31191b4e487SEugen Hristev /* Gamma table with gamma 1/2.2 */
31291b4e487SEugen Hristev static const u32 isc_sama5d2_gamma_table[][GAMMA_ENTRIES] = {
31391b4e487SEugen Hristev 	/* 0 --> gamma 1/1.8 */
31491b4e487SEugen Hristev 	{      0x65,  0x66002F,  0x950025,  0xBB0020,  0xDB001D,  0xF8001A,
31591b4e487SEugen Hristev 	  0x1130018, 0x12B0017, 0x1420016, 0x1580014, 0x16D0013, 0x1810012,
31691b4e487SEugen Hristev 	  0x1940012, 0x1A60012, 0x1B80011, 0x1C90010, 0x1DA0010, 0x1EA000F,
31791b4e487SEugen Hristev 	  0x1FA000F, 0x209000F, 0x218000F, 0x227000E, 0x235000E, 0x243000E,
31891b4e487SEugen Hristev 	  0x251000E, 0x25F000D, 0x26C000D, 0x279000D, 0x286000D, 0x293000C,
31991b4e487SEugen Hristev 	  0x2A0000C, 0x2AC000C, 0x2B8000C, 0x2C4000C, 0x2D0000B, 0x2DC000B,
32091b4e487SEugen Hristev 	  0x2E7000B, 0x2F3000B, 0x2FE000B, 0x309000B, 0x314000B, 0x31F000A,
32191b4e487SEugen Hristev 	  0x32A000A, 0x334000B, 0x33F000A, 0x349000A, 0x354000A, 0x35E000A,
32291b4e487SEugen Hristev 	  0x368000A, 0x372000A, 0x37C000A, 0x386000A, 0x3900009, 0x399000A,
32391b4e487SEugen Hristev 	  0x3A30009, 0x3AD0009, 0x3B60009, 0x3BF000A, 0x3C90009, 0x3D20009,
32491b4e487SEugen Hristev 	  0x3DB0009, 0x3E40009, 0x3ED0009, 0x3F60009 },
32591b4e487SEugen Hristev 
32691b4e487SEugen Hristev 	/* 1 --> gamma 1/2 */
32791b4e487SEugen Hristev 	{      0x7F,  0x800034,  0xB50028,  0xDE0021, 0x100001E, 0x11E001B,
32891b4e487SEugen Hristev 	  0x1390019, 0x1520017, 0x16A0015, 0x1800014, 0x1940014, 0x1A80013,
32991b4e487SEugen Hristev 	  0x1BB0012, 0x1CD0011, 0x1DF0010, 0x1EF0010, 0x200000F, 0x20F000F,
33091b4e487SEugen Hristev 	  0x21F000E, 0x22D000F, 0x23C000E, 0x24A000E, 0x258000D, 0x265000D,
33191b4e487SEugen Hristev 	  0x273000C, 0x27F000D, 0x28C000C, 0x299000C, 0x2A5000C, 0x2B1000B,
33291b4e487SEugen Hristev 	  0x2BC000C, 0x2C8000B, 0x2D3000C, 0x2DF000B, 0x2EA000A, 0x2F5000A,
33391b4e487SEugen Hristev 	  0x2FF000B, 0x30A000A, 0x314000B, 0x31F000A, 0x329000A, 0x333000A,
33491b4e487SEugen Hristev 	  0x33D0009, 0x3470009, 0x350000A, 0x35A0009, 0x363000A, 0x36D0009,
33591b4e487SEugen Hristev 	  0x3760009, 0x37F0009, 0x3880009, 0x3910009, 0x39A0009, 0x3A30009,
33691b4e487SEugen Hristev 	  0x3AC0008, 0x3B40009, 0x3BD0008, 0x3C60008, 0x3CE0008, 0x3D60009,
33791b4e487SEugen Hristev 	  0x3DF0008, 0x3E70008, 0x3EF0008, 0x3F70008 },
33891b4e487SEugen Hristev 
33991b4e487SEugen Hristev 	/* 2 --> gamma 1/2.2 */
34091b4e487SEugen Hristev 	{      0x99,  0x9B0038,  0xD4002A,  0xFF0023, 0x122001F, 0x141001B,
34191b4e487SEugen Hristev 	  0x15D0019, 0x1760017, 0x18E0015, 0x1A30015, 0x1B80013, 0x1CC0012,
34291b4e487SEugen Hristev 	  0x1DE0011, 0x1F00010, 0x2010010, 0x2110010, 0x221000F, 0x230000F,
34391b4e487SEugen Hristev 	  0x23F000E, 0x24D000E, 0x25B000D, 0x269000C, 0x276000C, 0x283000C,
34491b4e487SEugen Hristev 	  0x28F000C, 0x29B000C, 0x2A7000C, 0x2B3000B, 0x2BF000B, 0x2CA000B,
34591b4e487SEugen Hristev 	  0x2D5000B, 0x2E0000A, 0x2EB000A, 0x2F5000A, 0x2FF000A, 0x30A000A,
34691b4e487SEugen Hristev 	  0x3140009, 0x31E0009, 0x327000A, 0x3310009, 0x33A0009, 0x3440009,
34791b4e487SEugen Hristev 	  0x34D0009, 0x3560009, 0x35F0009, 0x3680008, 0x3710008, 0x3790009,
34891b4e487SEugen Hristev 	  0x3820008, 0x38A0008, 0x3930008, 0x39B0008, 0x3A30008, 0x3AB0008,
34991b4e487SEugen Hristev 	  0x3B30008, 0x3BB0008, 0x3C30008, 0x3CB0007, 0x3D20008, 0x3DA0007,
35091b4e487SEugen Hristev 	  0x3E20007, 0x3E90007, 0x3F00008, 0x3F80007 },
35191b4e487SEugen Hristev };
35291b4e487SEugen Hristev 
isc_parse_dt(struct device * dev,struct isc_device * isc)35391b4e487SEugen Hristev static int isc_parse_dt(struct device *dev, struct isc_device *isc)
35491b4e487SEugen Hristev {
35591b4e487SEugen Hristev 	struct device_node *np = dev->of_node;
35691b4e487SEugen Hristev 	struct device_node *epn = NULL;
35791b4e487SEugen Hristev 	struct isc_subdev_entity *subdev_entity;
35891b4e487SEugen Hristev 	unsigned int flags;
35991b4e487SEugen Hristev 	int ret;
36091b4e487SEugen Hristev 
36191b4e487SEugen Hristev 	INIT_LIST_HEAD(&isc->subdev_entities);
36291b4e487SEugen Hristev 
36391b4e487SEugen Hristev 	while (1) {
36491b4e487SEugen Hristev 		struct v4l2_fwnode_endpoint v4l2_epn = { .bus_type = 0 };
36591b4e487SEugen Hristev 
36691b4e487SEugen Hristev 		epn = of_graph_get_next_endpoint(np, epn);
36791b4e487SEugen Hristev 		if (!epn)
36891b4e487SEugen Hristev 			return 0;
36991b4e487SEugen Hristev 
37091b4e487SEugen Hristev 		ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(epn),
37191b4e487SEugen Hristev 						 &v4l2_epn);
37291b4e487SEugen Hristev 		if (ret) {
37391b4e487SEugen Hristev 			ret = -EINVAL;
37491b4e487SEugen Hristev 			dev_err(dev, "Could not parse the endpoint\n");
37591b4e487SEugen Hristev 			break;
37691b4e487SEugen Hristev 		}
37791b4e487SEugen Hristev 
37891b4e487SEugen Hristev 		subdev_entity = devm_kzalloc(dev, sizeof(*subdev_entity),
37991b4e487SEugen Hristev 					     GFP_KERNEL);
38091b4e487SEugen Hristev 		if (!subdev_entity) {
38191b4e487SEugen Hristev 			ret = -ENOMEM;
38291b4e487SEugen Hristev 			break;
38391b4e487SEugen Hristev 		}
38491b4e487SEugen Hristev 		subdev_entity->epn = epn;
38591b4e487SEugen Hristev 
38691b4e487SEugen Hristev 		flags = v4l2_epn.bus.parallel.flags;
38791b4e487SEugen Hristev 
38891b4e487SEugen Hristev 		if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
38991b4e487SEugen Hristev 			subdev_entity->pfe_cfg0 = ISC_PFE_CFG0_HPOL_LOW;
39091b4e487SEugen Hristev 
39191b4e487SEugen Hristev 		if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
39291b4e487SEugen Hristev 			subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_VPOL_LOW;
39391b4e487SEugen Hristev 
39491b4e487SEugen Hristev 		if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
39591b4e487SEugen Hristev 			subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_PPOL_LOW;
39691b4e487SEugen Hristev 
39791b4e487SEugen Hristev 		if (v4l2_epn.bus_type == V4L2_MBUS_BT656)
39891b4e487SEugen Hristev 			subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_CCIR_CRC |
39991b4e487SEugen Hristev 					ISC_PFE_CFG0_CCIR656;
40091b4e487SEugen Hristev 
40191b4e487SEugen Hristev 		list_add_tail(&subdev_entity->list, &isc->subdev_entities);
40291b4e487SEugen Hristev 	}
40391b4e487SEugen Hristev 	of_node_put(epn);
40491b4e487SEugen Hristev 
40591b4e487SEugen Hristev 	return ret;
40691b4e487SEugen Hristev }
40791b4e487SEugen Hristev 
microchip_isc_probe(struct platform_device * pdev)40891b4e487SEugen Hristev static int microchip_isc_probe(struct platform_device *pdev)
40991b4e487SEugen Hristev {
41091b4e487SEugen Hristev 	struct device *dev = &pdev->dev;
41191b4e487SEugen Hristev 	struct isc_device *isc;
41291b4e487SEugen Hristev 	void __iomem *io_base;
41391b4e487SEugen Hristev 	struct isc_subdev_entity *subdev_entity;
41491b4e487SEugen Hristev 	int irq;
41591b4e487SEugen Hristev 	int ret;
41691b4e487SEugen Hristev 	u32 ver;
41791b4e487SEugen Hristev 
41891b4e487SEugen Hristev 	isc = devm_kzalloc(dev, sizeof(*isc), GFP_KERNEL);
41991b4e487SEugen Hristev 	if (!isc)
42091b4e487SEugen Hristev 		return -ENOMEM;
42191b4e487SEugen Hristev 
42291b4e487SEugen Hristev 	platform_set_drvdata(pdev, isc);
42391b4e487SEugen Hristev 	isc->dev = dev;
42491b4e487SEugen Hristev 
425639a6fa4SYangtao Li 	io_base = devm_platform_ioremap_resource(pdev, 0);
42691b4e487SEugen Hristev 	if (IS_ERR(io_base))
42791b4e487SEugen Hristev 		return PTR_ERR(io_base);
42891b4e487SEugen Hristev 
42991b4e487SEugen Hristev 	isc->regmap = devm_regmap_init_mmio(dev, io_base, &microchip_isc_regmap_config);
43091b4e487SEugen Hristev 	if (IS_ERR(isc->regmap)) {
43191b4e487SEugen Hristev 		ret = PTR_ERR(isc->regmap);
43291b4e487SEugen Hristev 		dev_err(dev, "failed to init register map: %d\n", ret);
43391b4e487SEugen Hristev 		return ret;
43491b4e487SEugen Hristev 	}
43591b4e487SEugen Hristev 
43691b4e487SEugen Hristev 	irq = platform_get_irq(pdev, 0);
43791b4e487SEugen Hristev 	if (irq < 0)
43891b4e487SEugen Hristev 		return irq;
43991b4e487SEugen Hristev 
44091b4e487SEugen Hristev 	ret = devm_request_irq(dev, irq, microchip_isc_interrupt, 0,
44191b4e487SEugen Hristev 			       "microchip-sama5d2-isc", isc);
44291b4e487SEugen Hristev 	if (ret < 0) {
44391b4e487SEugen Hristev 		dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
44491b4e487SEugen Hristev 			irq, ret);
44591b4e487SEugen Hristev 		return ret;
44691b4e487SEugen Hristev 	}
44791b4e487SEugen Hristev 
44891b4e487SEugen Hristev 	isc->gamma_table = isc_sama5d2_gamma_table;
44991b4e487SEugen Hristev 	isc->gamma_max = 2;
45091b4e487SEugen Hristev 
45191b4e487SEugen Hristev 	isc->max_width = ISC_SAMA5D2_MAX_SUPPORT_WIDTH;
45291b4e487SEugen Hristev 	isc->max_height = ISC_SAMA5D2_MAX_SUPPORT_HEIGHT;
45391b4e487SEugen Hristev 
45491b4e487SEugen Hristev 	isc->config_dpc = isc_sama5d2_config_dpc;
45591b4e487SEugen Hristev 	isc->config_csc = isc_sama5d2_config_csc;
45691b4e487SEugen Hristev 	isc->config_cbc = isc_sama5d2_config_cbc;
45791b4e487SEugen Hristev 	isc->config_cc = isc_sama5d2_config_cc;
45891b4e487SEugen Hristev 	isc->config_gam = isc_sama5d2_config_gam;
45991b4e487SEugen Hristev 	isc->config_rlp = isc_sama5d2_config_rlp;
46091b4e487SEugen Hristev 	isc->config_ctrls = isc_sama5d2_config_ctrls;
46191b4e487SEugen Hristev 
46291b4e487SEugen Hristev 	isc->adapt_pipeline = isc_sama5d2_adapt_pipeline;
46391b4e487SEugen Hristev 
46491b4e487SEugen Hristev 	isc->offsets.csc = ISC_SAMA5D2_CSC_OFFSET;
46591b4e487SEugen Hristev 	isc->offsets.cbc = ISC_SAMA5D2_CBC_OFFSET;
46691b4e487SEugen Hristev 	isc->offsets.sub422 = ISC_SAMA5D2_SUB422_OFFSET;
46791b4e487SEugen Hristev 	isc->offsets.sub420 = ISC_SAMA5D2_SUB420_OFFSET;
46891b4e487SEugen Hristev 	isc->offsets.rlp = ISC_SAMA5D2_RLP_OFFSET;
46991b4e487SEugen Hristev 	isc->offsets.his = ISC_SAMA5D2_HIS_OFFSET;
47091b4e487SEugen Hristev 	isc->offsets.dma = ISC_SAMA5D2_DMA_OFFSET;
47191b4e487SEugen Hristev 	isc->offsets.version = ISC_SAMA5D2_VERSION_OFFSET;
47291b4e487SEugen Hristev 	isc->offsets.his_entry = ISC_SAMA5D2_HIS_ENTRY_OFFSET;
47391b4e487SEugen Hristev 
47491b4e487SEugen Hristev 	isc->controller_formats = sama5d2_controller_formats;
47591b4e487SEugen Hristev 	isc->controller_formats_size = ARRAY_SIZE(sama5d2_controller_formats);
47691b4e487SEugen Hristev 	isc->formats_list = sama5d2_formats_list;
47791b4e487SEugen Hristev 	isc->formats_list_size = ARRAY_SIZE(sama5d2_formats_list);
47891b4e487SEugen Hristev 
47991b4e487SEugen Hristev 	/* sama5d2-isc - 8 bits per beat */
48091b4e487SEugen Hristev 	isc->dcfg = ISC_DCFG_YMBSIZE_BEATS8 | ISC_DCFG_CMBSIZE_BEATS8;
48191b4e487SEugen Hristev 
48291b4e487SEugen Hristev 	/* sama5d2-isc : ISPCK is required and mandatory */
48391b4e487SEugen Hristev 	isc->ispck_required = true;
48491b4e487SEugen Hristev 
48591b4e487SEugen Hristev 	ret = microchip_isc_pipeline_init(isc);
48691b4e487SEugen Hristev 	if (ret)
48791b4e487SEugen Hristev 		return ret;
48891b4e487SEugen Hristev 
48991b4e487SEugen Hristev 	isc->hclock = devm_clk_get(dev, "hclock");
49091b4e487SEugen Hristev 	if (IS_ERR(isc->hclock)) {
49191b4e487SEugen Hristev 		ret = PTR_ERR(isc->hclock);
49291b4e487SEugen Hristev 		dev_err(dev, "failed to get hclock: %d\n", ret);
49391b4e487SEugen Hristev 		return ret;
49491b4e487SEugen Hristev 	}
49591b4e487SEugen Hristev 
49691b4e487SEugen Hristev 	ret = clk_prepare_enable(isc->hclock);
49791b4e487SEugen Hristev 	if (ret) {
49891b4e487SEugen Hristev 		dev_err(dev, "failed to enable hclock: %d\n", ret);
49991b4e487SEugen Hristev 		return ret;
50091b4e487SEugen Hristev 	}
50191b4e487SEugen Hristev 
50291b4e487SEugen Hristev 	ret = microchip_isc_clk_init(isc);
50391b4e487SEugen Hristev 	if (ret) {
50491b4e487SEugen Hristev 		dev_err(dev, "failed to init isc clock: %d\n", ret);
50591b4e487SEugen Hristev 		goto unprepare_hclk;
50691b4e487SEugen Hristev 	}
50791b4e487SEugen Hristev 	ret = v4l2_device_register(dev, &isc->v4l2_dev);
50891b4e487SEugen Hristev 	if (ret) {
50991b4e487SEugen Hristev 		dev_err(dev, "unable to register v4l2 device.\n");
51091b4e487SEugen Hristev 		goto unprepare_clk;
51191b4e487SEugen Hristev 	}
51291b4e487SEugen Hristev 
51391b4e487SEugen Hristev 	ret = isc_parse_dt(dev, isc);
51491b4e487SEugen Hristev 	if (ret) {
51591b4e487SEugen Hristev 		dev_err(dev, "fail to parse device tree\n");
51691b4e487SEugen Hristev 		goto unregister_v4l2_device;
51791b4e487SEugen Hristev 	}
51891b4e487SEugen Hristev 
51991b4e487SEugen Hristev 	if (list_empty(&isc->subdev_entities)) {
52091b4e487SEugen Hristev 		dev_err(dev, "no subdev found\n");
52191b4e487SEugen Hristev 		ret = -ENODEV;
52291b4e487SEugen Hristev 		goto unregister_v4l2_device;
52391b4e487SEugen Hristev 	}
52491b4e487SEugen Hristev 
52591b4e487SEugen Hristev 	list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
526adb2dcd5SSakari Ailus 		struct v4l2_async_connection *asd;
52791b4e487SEugen Hristev 		struct fwnode_handle *fwnode =
52891b4e487SEugen Hristev 			of_fwnode_handle(subdev_entity->epn);
52991b4e487SEugen Hristev 
530*b8ec754aSSakari Ailus 		v4l2_async_nf_init(&subdev_entity->notifier, &isc->v4l2_dev);
53191b4e487SEugen Hristev 
53291b4e487SEugen Hristev 		asd = v4l2_async_nf_add_fwnode_remote(&subdev_entity->notifier,
53391b4e487SEugen Hristev 						      fwnode,
534adb2dcd5SSakari Ailus 						      struct v4l2_async_connection);
53591b4e487SEugen Hristev 
53691b4e487SEugen Hristev 		of_node_put(subdev_entity->epn);
53791b4e487SEugen Hristev 		subdev_entity->epn = NULL;
53891b4e487SEugen Hristev 
53991b4e487SEugen Hristev 		if (IS_ERR(asd)) {
54091b4e487SEugen Hristev 			ret = PTR_ERR(asd);
54191b4e487SEugen Hristev 			goto cleanup_subdev;
54291b4e487SEugen Hristev 		}
54391b4e487SEugen Hristev 
54491b4e487SEugen Hristev 		subdev_entity->notifier.ops = &microchip_isc_async_ops;
54591b4e487SEugen Hristev 
546*b8ec754aSSakari Ailus 		ret = v4l2_async_nf_register(&subdev_entity->notifier);
54791b4e487SEugen Hristev 		if (ret) {
54891b4e487SEugen Hristev 			dev_err(dev, "fail to register async notifier\n");
54991b4e487SEugen Hristev 			goto cleanup_subdev;
55091b4e487SEugen Hristev 		}
55191b4e487SEugen Hristev 
55291b4e487SEugen Hristev 		if (video_is_registered(&isc->video_dev))
55391b4e487SEugen Hristev 			break;
55491b4e487SEugen Hristev 	}
55591b4e487SEugen Hristev 
556920b2665SEugen Hristev 	regmap_read(isc->regmap, ISC_VERSION + isc->offsets.version, &ver);
557920b2665SEugen Hristev 
558920b2665SEugen Hristev 	ret = isc_mc_init(isc, ver);
559920b2665SEugen Hristev 	if (ret < 0)
560920b2665SEugen Hristev 		goto isc_probe_mc_init_err;
561920b2665SEugen Hristev 
56291b4e487SEugen Hristev 	pm_runtime_set_active(dev);
56391b4e487SEugen Hristev 	pm_runtime_enable(dev);
56491b4e487SEugen Hristev 	pm_request_idle(dev);
56591b4e487SEugen Hristev 
56691b4e487SEugen Hristev 	isc->ispck = isc->isc_clks[ISC_ISPCK].clk;
56791b4e487SEugen Hristev 
56891b4e487SEugen Hristev 	ret = clk_prepare_enable(isc->ispck);
56991b4e487SEugen Hristev 	if (ret) {
57091b4e487SEugen Hristev 		dev_err(dev, "failed to enable ispck: %d\n", ret);
57191b4e487SEugen Hristev 		goto disable_pm;
57291b4e487SEugen Hristev 	}
57391b4e487SEugen Hristev 
57491b4e487SEugen Hristev 	/* ispck should be greater or equal to hclock */
57591b4e487SEugen Hristev 	ret = clk_set_rate(isc->ispck, clk_get_rate(isc->hclock));
57691b4e487SEugen Hristev 	if (ret) {
57791b4e487SEugen Hristev 		dev_err(dev, "failed to set ispck rate: %d\n", ret);
57891b4e487SEugen Hristev 		goto unprepare_clk;
57991b4e487SEugen Hristev 	}
58091b4e487SEugen Hristev 
58191b4e487SEugen Hristev 	dev_info(dev, "Microchip ISC version %x\n", ver);
58291b4e487SEugen Hristev 
58391b4e487SEugen Hristev 	return 0;
58491b4e487SEugen Hristev 
58591b4e487SEugen Hristev unprepare_clk:
58691b4e487SEugen Hristev 	clk_disable_unprepare(isc->ispck);
58791b4e487SEugen Hristev 
58891b4e487SEugen Hristev disable_pm:
58991b4e487SEugen Hristev 	pm_runtime_disable(dev);
59091b4e487SEugen Hristev 
591920b2665SEugen Hristev isc_probe_mc_init_err:
592920b2665SEugen Hristev 	isc_mc_cleanup(isc);
593920b2665SEugen Hristev 
59491b4e487SEugen Hristev cleanup_subdev:
59591b4e487SEugen Hristev 	microchip_isc_subdev_cleanup(isc);
59691b4e487SEugen Hristev 
59791b4e487SEugen Hristev unregister_v4l2_device:
59891b4e487SEugen Hristev 	v4l2_device_unregister(&isc->v4l2_dev);
59991b4e487SEugen Hristev 
60091b4e487SEugen Hristev unprepare_hclk:
60191b4e487SEugen Hristev 	clk_disable_unprepare(isc->hclock);
60291b4e487SEugen Hristev 
60391b4e487SEugen Hristev 	microchip_isc_clk_cleanup(isc);
60491b4e487SEugen Hristev 
60591b4e487SEugen Hristev 	return ret;
60691b4e487SEugen Hristev }
60791b4e487SEugen Hristev 
microchip_isc_remove(struct platform_device * pdev)60861263f17SUwe Kleine-König static void microchip_isc_remove(struct platform_device *pdev)
60991b4e487SEugen Hristev {
61091b4e487SEugen Hristev 	struct isc_device *isc = platform_get_drvdata(pdev);
61191b4e487SEugen Hristev 
61291b4e487SEugen Hristev 	pm_runtime_disable(&pdev->dev);
61391b4e487SEugen Hristev 
614920b2665SEugen Hristev 	isc_mc_cleanup(isc);
615920b2665SEugen Hristev 
61691b4e487SEugen Hristev 	microchip_isc_subdev_cleanup(isc);
61791b4e487SEugen Hristev 
61891b4e487SEugen Hristev 	v4l2_device_unregister(&isc->v4l2_dev);
61991b4e487SEugen Hristev 
62091b4e487SEugen Hristev 	clk_disable_unprepare(isc->ispck);
62191b4e487SEugen Hristev 	clk_disable_unprepare(isc->hclock);
62291b4e487SEugen Hristev 
62391b4e487SEugen Hristev 	microchip_isc_clk_cleanup(isc);
62491b4e487SEugen Hristev }
62591b4e487SEugen Hristev 
isc_runtime_suspend(struct device * dev)62691b4e487SEugen Hristev static int __maybe_unused isc_runtime_suspend(struct device *dev)
62791b4e487SEugen Hristev {
62891b4e487SEugen Hristev 	struct isc_device *isc = dev_get_drvdata(dev);
62991b4e487SEugen Hristev 
63091b4e487SEugen Hristev 	clk_disable_unprepare(isc->ispck);
63191b4e487SEugen Hristev 	clk_disable_unprepare(isc->hclock);
63291b4e487SEugen Hristev 
63391b4e487SEugen Hristev 	return 0;
63491b4e487SEugen Hristev }
63591b4e487SEugen Hristev 
isc_runtime_resume(struct device * dev)63691b4e487SEugen Hristev static int __maybe_unused isc_runtime_resume(struct device *dev)
63791b4e487SEugen Hristev {
63891b4e487SEugen Hristev 	struct isc_device *isc = dev_get_drvdata(dev);
63991b4e487SEugen Hristev 	int ret;
64091b4e487SEugen Hristev 
64191b4e487SEugen Hristev 	ret = clk_prepare_enable(isc->hclock);
64291b4e487SEugen Hristev 	if (ret)
64391b4e487SEugen Hristev 		return ret;
64491b4e487SEugen Hristev 
64591b4e487SEugen Hristev 	ret = clk_prepare_enable(isc->ispck);
64691b4e487SEugen Hristev 	if (ret)
64791b4e487SEugen Hristev 		clk_disable_unprepare(isc->hclock);
64891b4e487SEugen Hristev 
64991b4e487SEugen Hristev 	return ret;
65091b4e487SEugen Hristev }
65191b4e487SEugen Hristev 
65291b4e487SEugen Hristev static const struct dev_pm_ops microchip_isc_dev_pm_ops = {
65391b4e487SEugen Hristev 	SET_RUNTIME_PM_OPS(isc_runtime_suspend, isc_runtime_resume, NULL)
65491b4e487SEugen Hristev };
65591b4e487SEugen Hristev 
65691b4e487SEugen Hristev #if IS_ENABLED(CONFIG_OF)
65791b4e487SEugen Hristev static const struct of_device_id microchip_isc_of_match[] = {
65891b4e487SEugen Hristev 	{ .compatible = "atmel,sama5d2-isc" },
65991b4e487SEugen Hristev 	{ }
66091b4e487SEugen Hristev };
66191b4e487SEugen Hristev MODULE_DEVICE_TABLE(of, microchip_isc_of_match);
66291b4e487SEugen Hristev #endif
66391b4e487SEugen Hristev 
66491b4e487SEugen Hristev static struct platform_driver microchip_isc_driver = {
66591b4e487SEugen Hristev 	.probe	= microchip_isc_probe,
66661263f17SUwe Kleine-König 	.remove_new = microchip_isc_remove,
66791b4e487SEugen Hristev 	.driver	= {
66891b4e487SEugen Hristev 		.name		= "microchip-sama5d2-isc",
66991b4e487SEugen Hristev 		.pm		= &microchip_isc_dev_pm_ops,
67091b4e487SEugen Hristev 		.of_match_table = of_match_ptr(microchip_isc_of_match),
67191b4e487SEugen Hristev 	},
67291b4e487SEugen Hristev };
67391b4e487SEugen Hristev 
67491b4e487SEugen Hristev module_platform_driver(microchip_isc_driver);
67591b4e487SEugen Hristev 
67691b4e487SEugen Hristev MODULE_AUTHOR("Songjun Wu");
67791b4e487SEugen Hristev MODULE_DESCRIPTION("The V4L2 driver for Microchip-ISC");
67891b4e487SEugen Hristev MODULE_LICENSE("GPL v2");
679