162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Microchip eXtended Image Sensor Controller (XISC) driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2019-2021 Microchip Technology, Inc. and its subsidiaries
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Author: Eugen Hristev <eugen.hristev@microchip.com>
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * Sensor-->PFE-->DPC-->WB-->CFA-->CC-->GAM-->VHXS-->CSC-->CBHS-->SUB-->RLP-->DMA-->HIS
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * ISC video pipeline integrates the following submodules:
1262306a36Sopenharmony_ci * PFE: Parallel Front End to sample the camera sensor input stream
1362306a36Sopenharmony_ci * DPC: Defective Pixel Correction with black offset correction, green disparity
1462306a36Sopenharmony_ci *      correction and defective pixel correction (3 modules total)
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 *VHXS: Vertical and Horizontal Scaler
2062306a36Sopenharmony_ci * CSC: Programmable color space conversion
2162306a36Sopenharmony_ci *CBHS: Contrast Brightness Hue and Saturation control
2262306a36Sopenharmony_ci * SUB: This module performs YCbCr444 to YCbCr420 chrominance subsampling
2362306a36Sopenharmony_ci * RLP: This module performs rounding, range limiting
2462306a36Sopenharmony_ci *      and packing of the incoming data
2562306a36Sopenharmony_ci * DMA: This module performs DMA master accesses to write frames to external RAM
2662306a36Sopenharmony_ci * HIS: Histogram module performs statistic counters on the frames
2762306a36Sopenharmony_ci */
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#include <linux/clk.h>
3062306a36Sopenharmony_ci#include <linux/clkdev.h>
3162306a36Sopenharmony_ci#include <linux/clk-provider.h>
3262306a36Sopenharmony_ci#include <linux/delay.h>
3362306a36Sopenharmony_ci#include <linux/interrupt.h>
3462306a36Sopenharmony_ci#include <linux/math64.h>
3562306a36Sopenharmony_ci#include <linux/module.h>
3662306a36Sopenharmony_ci#include <linux/of.h>
3762306a36Sopenharmony_ci#include <linux/of_graph.h>
3862306a36Sopenharmony_ci#include <linux/platform_device.h>
3962306a36Sopenharmony_ci#include <linux/pm_runtime.h>
4062306a36Sopenharmony_ci#include <linux/regmap.h>
4162306a36Sopenharmony_ci#include <linux/videodev2.h>
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#include <media/v4l2-ctrls.h>
4462306a36Sopenharmony_ci#include <media/v4l2-device.h>
4562306a36Sopenharmony_ci#include <media/v4l2-event.h>
4662306a36Sopenharmony_ci#include <media/v4l2-image-sizes.h>
4762306a36Sopenharmony_ci#include <media/v4l2-ioctl.h>
4862306a36Sopenharmony_ci#include <media/v4l2-fwnode.h>
4962306a36Sopenharmony_ci#include <media/v4l2-subdev.h>
5062306a36Sopenharmony_ci#include <media/videobuf2-dma-contig.h>
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#include "microchip-isc-regs.h"
5362306a36Sopenharmony_ci#include "microchip-isc.h"
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci#define ISC_SAMA7G5_MAX_SUPPORT_WIDTH   3264
5662306a36Sopenharmony_ci#define ISC_SAMA7G5_MAX_SUPPORT_HEIGHT  2464
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci#define ISC_SAMA7G5_PIPELINE \
5962306a36Sopenharmony_ci	(WB_ENABLE | CFA_ENABLE | CC_ENABLE | GAM_ENABLES | CSC_ENABLE | \
6062306a36Sopenharmony_ci	CBC_ENABLE | SUB422_ENABLE | SUB420_ENABLE)
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci/* This is a list of the formats that the ISC can *output* */
6362306a36Sopenharmony_cistatic const struct isc_format sama7g5_controller_formats[] = {
6462306a36Sopenharmony_ci	{
6562306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_ARGB444,
6662306a36Sopenharmony_ci	}, {
6762306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_ARGB555,
6862306a36Sopenharmony_ci	}, {
6962306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_RGB565,
7062306a36Sopenharmony_ci	}, {
7162306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_ABGR32,
7262306a36Sopenharmony_ci	}, {
7362306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_XBGR32,
7462306a36Sopenharmony_ci	}, {
7562306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_YUV420,
7662306a36Sopenharmony_ci	}, {
7762306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_UYVY,
7862306a36Sopenharmony_ci	}, {
7962306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_VYUY,
8062306a36Sopenharmony_ci	}, {
8162306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_YUYV,
8262306a36Sopenharmony_ci	}, {
8362306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_YUV422P,
8462306a36Sopenharmony_ci	}, {
8562306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_GREY,
8662306a36Sopenharmony_ci	}, {
8762306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_Y10,
8862306a36Sopenharmony_ci	}, {
8962306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_Y16,
9062306a36Sopenharmony_ci	}, {
9162306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SBGGR8,
9262306a36Sopenharmony_ci		.raw		= true,
9362306a36Sopenharmony_ci	}, {
9462306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SGBRG8,
9562306a36Sopenharmony_ci		.raw		= true,
9662306a36Sopenharmony_ci	}, {
9762306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SGRBG8,
9862306a36Sopenharmony_ci		.raw		= true,
9962306a36Sopenharmony_ci	}, {
10062306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SRGGB8,
10162306a36Sopenharmony_ci		.raw		= true,
10262306a36Sopenharmony_ci	}, {
10362306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SBGGR10,
10462306a36Sopenharmony_ci		.raw		= true,
10562306a36Sopenharmony_ci	}, {
10662306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SGBRG10,
10762306a36Sopenharmony_ci		.raw		= true,
10862306a36Sopenharmony_ci	}, {
10962306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SGRBG10,
11062306a36Sopenharmony_ci		.raw		= true,
11162306a36Sopenharmony_ci	}, {
11262306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SRGGB10,
11362306a36Sopenharmony_ci		.raw		= true,
11462306a36Sopenharmony_ci	}, {
11562306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SBGGR12,
11662306a36Sopenharmony_ci		.raw		= true,
11762306a36Sopenharmony_ci	}, {
11862306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SGBRG12,
11962306a36Sopenharmony_ci		.raw		= true,
12062306a36Sopenharmony_ci	}, {
12162306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SGRBG12,
12262306a36Sopenharmony_ci		.raw		= true,
12362306a36Sopenharmony_ci	}, {
12462306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SRGGB12,
12562306a36Sopenharmony_ci		.raw		= true,
12662306a36Sopenharmony_ci	},
12762306a36Sopenharmony_ci};
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci/* This is a list of formats that the ISC can receive as *input* */
13062306a36Sopenharmony_cistatic struct isc_format sama7g5_formats_list[] = {
13162306a36Sopenharmony_ci	{
13262306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SBGGR8,
13362306a36Sopenharmony_ci		.mbus_code	= MEDIA_BUS_FMT_SBGGR8_1X8,
13462306a36Sopenharmony_ci		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,
13562306a36Sopenharmony_ci		.cfa_baycfg	= ISC_BAY_CFG_BGBG,
13662306a36Sopenharmony_ci	},
13762306a36Sopenharmony_ci	{
13862306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SGBRG8,
13962306a36Sopenharmony_ci		.mbus_code	= MEDIA_BUS_FMT_SGBRG8_1X8,
14062306a36Sopenharmony_ci		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,
14162306a36Sopenharmony_ci		.cfa_baycfg	= ISC_BAY_CFG_GBGB,
14262306a36Sopenharmony_ci	},
14362306a36Sopenharmony_ci	{
14462306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SGRBG8,
14562306a36Sopenharmony_ci		.mbus_code	= MEDIA_BUS_FMT_SGRBG8_1X8,
14662306a36Sopenharmony_ci		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,
14762306a36Sopenharmony_ci		.cfa_baycfg	= ISC_BAY_CFG_GRGR,
14862306a36Sopenharmony_ci	},
14962306a36Sopenharmony_ci	{
15062306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SRGGB8,
15162306a36Sopenharmony_ci		.mbus_code	= MEDIA_BUS_FMT_SRGGB8_1X8,
15262306a36Sopenharmony_ci		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,
15362306a36Sopenharmony_ci		.cfa_baycfg	= ISC_BAY_CFG_RGRG,
15462306a36Sopenharmony_ci	},
15562306a36Sopenharmony_ci	{
15662306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SBGGR10,
15762306a36Sopenharmony_ci		.mbus_code	= MEDIA_BUS_FMT_SBGGR10_1X10,
15862306a36Sopenharmony_ci		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TEN,
15962306a36Sopenharmony_ci		.cfa_baycfg	= ISC_BAY_CFG_RGRG,
16062306a36Sopenharmony_ci	},
16162306a36Sopenharmony_ci	{
16262306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SGBRG10,
16362306a36Sopenharmony_ci		.mbus_code	= MEDIA_BUS_FMT_SGBRG10_1X10,
16462306a36Sopenharmony_ci		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TEN,
16562306a36Sopenharmony_ci		.cfa_baycfg	= ISC_BAY_CFG_GBGB,
16662306a36Sopenharmony_ci	},
16762306a36Sopenharmony_ci	{
16862306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SGRBG10,
16962306a36Sopenharmony_ci		.mbus_code	= MEDIA_BUS_FMT_SGRBG10_1X10,
17062306a36Sopenharmony_ci		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TEN,
17162306a36Sopenharmony_ci		.cfa_baycfg	= ISC_BAY_CFG_GRGR,
17262306a36Sopenharmony_ci	},
17362306a36Sopenharmony_ci	{
17462306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SRGGB10,
17562306a36Sopenharmony_ci		.mbus_code	= MEDIA_BUS_FMT_SRGGB10_1X10,
17662306a36Sopenharmony_ci		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TEN,
17762306a36Sopenharmony_ci		.cfa_baycfg	= ISC_BAY_CFG_RGRG,
17862306a36Sopenharmony_ci	},
17962306a36Sopenharmony_ci	{
18062306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SBGGR12,
18162306a36Sopenharmony_ci		.mbus_code	= MEDIA_BUS_FMT_SBGGR12_1X12,
18262306a36Sopenharmony_ci		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TWELVE,
18362306a36Sopenharmony_ci		.cfa_baycfg	= ISC_BAY_CFG_BGBG,
18462306a36Sopenharmony_ci	},
18562306a36Sopenharmony_ci	{
18662306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SGBRG12,
18762306a36Sopenharmony_ci		.mbus_code	= MEDIA_BUS_FMT_SGBRG12_1X12,
18862306a36Sopenharmony_ci		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TWELVE,
18962306a36Sopenharmony_ci		.cfa_baycfg	= ISC_BAY_CFG_GBGB,
19062306a36Sopenharmony_ci	},
19162306a36Sopenharmony_ci	{
19262306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SGRBG12,
19362306a36Sopenharmony_ci		.mbus_code	= MEDIA_BUS_FMT_SGRBG12_1X12,
19462306a36Sopenharmony_ci		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TWELVE,
19562306a36Sopenharmony_ci		.cfa_baycfg	= ISC_BAY_CFG_GRGR,
19662306a36Sopenharmony_ci	},
19762306a36Sopenharmony_ci	{
19862306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_SRGGB12,
19962306a36Sopenharmony_ci		.mbus_code	= MEDIA_BUS_FMT_SRGGB12_1X12,
20062306a36Sopenharmony_ci		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TWELVE,
20162306a36Sopenharmony_ci		.cfa_baycfg	= ISC_BAY_CFG_RGRG,
20262306a36Sopenharmony_ci	},
20362306a36Sopenharmony_ci	{
20462306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_GREY,
20562306a36Sopenharmony_ci		.mbus_code	= MEDIA_BUS_FMT_Y8_1X8,
20662306a36Sopenharmony_ci		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,
20762306a36Sopenharmony_ci	},
20862306a36Sopenharmony_ci	{
20962306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_YUYV,
21062306a36Sopenharmony_ci		.mbus_code	= MEDIA_BUS_FMT_YUYV8_2X8,
21162306a36Sopenharmony_ci		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,
21262306a36Sopenharmony_ci	},
21362306a36Sopenharmony_ci	{
21462306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_UYVY,
21562306a36Sopenharmony_ci		.mbus_code	= MEDIA_BUS_FMT_UYVY8_2X8,
21662306a36Sopenharmony_ci		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,
21762306a36Sopenharmony_ci	},
21862306a36Sopenharmony_ci	{
21962306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_RGB565,
22062306a36Sopenharmony_ci		.mbus_code	= MEDIA_BUS_FMT_RGB565_2X8_LE,
22162306a36Sopenharmony_ci		.pfe_cfg0_bps	= ISC_PFE_CFG0_BPS_EIGHT,
22262306a36Sopenharmony_ci	},
22362306a36Sopenharmony_ci	{
22462306a36Sopenharmony_ci		.fourcc		= V4L2_PIX_FMT_Y10,
22562306a36Sopenharmony_ci		.mbus_code	= MEDIA_BUS_FMT_Y10_1X10,
22662306a36Sopenharmony_ci		.pfe_cfg0_bps	= ISC_PFG_CFG0_BPS_TEN,
22762306a36Sopenharmony_ci	},
22862306a36Sopenharmony_ci};
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cistatic void isc_sama7g5_config_csc(struct isc_device *isc)
23162306a36Sopenharmony_ci{
23262306a36Sopenharmony_ci	struct regmap *regmap = isc->regmap;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	/* Convert RGB to YUV */
23562306a36Sopenharmony_ci	regmap_write(regmap, ISC_CSC_YR_YG + isc->offsets.csc,
23662306a36Sopenharmony_ci		     0x42 | (0x81 << 16));
23762306a36Sopenharmony_ci	regmap_write(regmap, ISC_CSC_YB_OY + isc->offsets.csc,
23862306a36Sopenharmony_ci		     0x19 | (0x10 << 16));
23962306a36Sopenharmony_ci	regmap_write(regmap, ISC_CSC_CBR_CBG + isc->offsets.csc,
24062306a36Sopenharmony_ci		     0xFDA | (0xFB6 << 16));
24162306a36Sopenharmony_ci	regmap_write(regmap, ISC_CSC_CBB_OCB + isc->offsets.csc,
24262306a36Sopenharmony_ci		     0x70 | (0x80 << 16));
24362306a36Sopenharmony_ci	regmap_write(regmap, ISC_CSC_CRR_CRG + isc->offsets.csc,
24462306a36Sopenharmony_ci		     0x70 | (0xFA2 << 16));
24562306a36Sopenharmony_ci	regmap_write(regmap, ISC_CSC_CRB_OCR + isc->offsets.csc,
24662306a36Sopenharmony_ci		     0xFEE | (0x80 << 16));
24762306a36Sopenharmony_ci}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cistatic void isc_sama7g5_config_cbc(struct isc_device *isc)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	struct regmap *regmap = isc->regmap;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	/* Configure what is set via v4l2 ctrls */
25462306a36Sopenharmony_ci	regmap_write(regmap, ISC_CBC_BRIGHT + isc->offsets.cbc, isc->ctrls.brightness);
25562306a36Sopenharmony_ci	regmap_write(regmap, ISC_CBC_CONTRAST + isc->offsets.cbc, isc->ctrls.contrast);
25662306a36Sopenharmony_ci	/* Configure Hue and Saturation as neutral midpoint */
25762306a36Sopenharmony_ci	regmap_write(regmap, ISC_CBCHS_HUE, 0);
25862306a36Sopenharmony_ci	regmap_write(regmap, ISC_CBCHS_SAT, (1 << 4));
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_cistatic void isc_sama7g5_config_cc(struct isc_device *isc)
26262306a36Sopenharmony_ci{
26362306a36Sopenharmony_ci	struct regmap *regmap = isc->regmap;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	/* Configure each register at the neutral fixed point 1.0 or 0.0 */
26662306a36Sopenharmony_ci	regmap_write(regmap, ISC_CC_RR_RG, (1 << 8));
26762306a36Sopenharmony_ci	regmap_write(regmap, ISC_CC_RB_OR, 0);
26862306a36Sopenharmony_ci	regmap_write(regmap, ISC_CC_GR_GG, (1 << 8) << 16);
26962306a36Sopenharmony_ci	regmap_write(regmap, ISC_CC_GB_OG, 0);
27062306a36Sopenharmony_ci	regmap_write(regmap, ISC_CC_BR_BG, 0);
27162306a36Sopenharmony_ci	regmap_write(regmap, ISC_CC_BB_OB, (1 << 8));
27262306a36Sopenharmony_ci}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_cistatic void isc_sama7g5_config_ctrls(struct isc_device *isc,
27562306a36Sopenharmony_ci				     const struct v4l2_ctrl_ops *ops)
27662306a36Sopenharmony_ci{
27762306a36Sopenharmony_ci	struct isc_ctrls *ctrls = &isc->ctrls;
27862306a36Sopenharmony_ci	struct v4l2_ctrl_handler *hdl = &ctrls->handler;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	ctrls->contrast = 16;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -2048, 2047, 1, 16);
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_cistatic void isc_sama7g5_config_dpc(struct isc_device *isc)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	u32 bay_cfg = isc->config.sd_format->cfa_baycfg;
28862306a36Sopenharmony_ci	struct regmap *regmap = isc->regmap;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	regmap_update_bits(regmap, ISC_DPC_CFG, ISC_DPC_CFG_BLOFF_MASK,
29162306a36Sopenharmony_ci			   (64 << ISC_DPC_CFG_BLOFF_SHIFT));
29262306a36Sopenharmony_ci	regmap_update_bits(regmap, ISC_DPC_CFG, ISC_DPC_CFG_BAYCFG_MASK,
29362306a36Sopenharmony_ci			   (bay_cfg << ISC_DPC_CFG_BAYCFG_SHIFT));
29462306a36Sopenharmony_ci}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_cistatic void isc_sama7g5_config_gam(struct isc_device *isc)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	struct regmap *regmap = isc->regmap;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	regmap_update_bits(regmap, ISC_GAM_CTRL, ISC_GAM_CTRL_BIPART,
30162306a36Sopenharmony_ci			   ISC_GAM_CTRL_BIPART);
30262306a36Sopenharmony_ci}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_cistatic void isc_sama7g5_config_rlp(struct isc_device *isc)
30562306a36Sopenharmony_ci{
30662306a36Sopenharmony_ci	struct regmap *regmap = isc->regmap;
30762306a36Sopenharmony_ci	u32 rlp_mode = isc->config.rlp_cfg_mode;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	regmap_update_bits(regmap, ISC_RLP_CFG + isc->offsets.rlp,
31062306a36Sopenharmony_ci			   ISC_RLP_CFG_MODE_MASK | ISC_RLP_CFG_LSH |
31162306a36Sopenharmony_ci			   ISC_RLP_CFG_YMODE_MASK, rlp_mode);
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_cistatic void isc_sama7g5_adapt_pipeline(struct isc_device *isc)
31562306a36Sopenharmony_ci{
31662306a36Sopenharmony_ci	isc->try_config.bits_pipeline &= ISC_SAMA7G5_PIPELINE;
31762306a36Sopenharmony_ci}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci/* Gamma table with gamma 1/2.2 */
32062306a36Sopenharmony_cistatic const u32 isc_sama7g5_gamma_table[][GAMMA_ENTRIES] = {
32162306a36Sopenharmony_ci	/* index 0 --> gamma bipartite */
32262306a36Sopenharmony_ci	{
32362306a36Sopenharmony_ci	      0x980,  0x4c0320,  0x650260,  0x7801e0,  0x8701a0,  0x940180,
32462306a36Sopenharmony_ci	   0xa00160,  0xab0120,  0xb40120,  0xbd0120,  0xc60100,  0xce0100,
32562306a36Sopenharmony_ci	   0xd600e0,  0xdd00e0,  0xe400e0,  0xeb00c0,  0xf100c0,  0xf700c0,
32662306a36Sopenharmony_ci	   0xfd00c0, 0x10300a0, 0x10800c0, 0x10e00a0, 0x11300a0, 0x11800a0,
32762306a36Sopenharmony_ci	  0x11d00a0, 0x12200a0, 0x12700a0, 0x12c0080, 0x13000a0, 0x1350080,
32862306a36Sopenharmony_ci	  0x13900a0, 0x13e0080, 0x1420076, 0x17d0062, 0x1ae0054, 0x1d8004a,
32962306a36Sopenharmony_ci	  0x1fd0044, 0x21f003e, 0x23e003a, 0x25b0036, 0x2760032, 0x28f0030,
33062306a36Sopenharmony_ci	  0x2a7002e, 0x2be002c, 0x2d4002c, 0x2ea0028, 0x2fe0028, 0x3120026,
33162306a36Sopenharmony_ci	  0x3250024, 0x3370024, 0x3490022, 0x35a0022, 0x36b0020, 0x37b0020,
33262306a36Sopenharmony_ci	  0x38b0020, 0x39b001e, 0x3aa001e, 0x3b9001c, 0x3c7001c, 0x3d5001c,
33362306a36Sopenharmony_ci	  0x3e3001c, 0x3f1001c, 0x3ff001a, 0x40c001a },
33462306a36Sopenharmony_ci};
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_cistatic int xisc_parse_dt(struct device *dev, struct isc_device *isc)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	struct device_node *np = dev->of_node;
33962306a36Sopenharmony_ci	struct device_node *epn = NULL;
34062306a36Sopenharmony_ci	struct isc_subdev_entity *subdev_entity;
34162306a36Sopenharmony_ci	unsigned int flags;
34262306a36Sopenharmony_ci	int ret;
34362306a36Sopenharmony_ci	bool mipi_mode;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	INIT_LIST_HEAD(&isc->subdev_entities);
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	mipi_mode = of_property_read_bool(np, "microchip,mipi-mode");
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	while (1) {
35062306a36Sopenharmony_ci		struct v4l2_fwnode_endpoint v4l2_epn = { .bus_type = 0 };
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci		epn = of_graph_get_next_endpoint(np, epn);
35362306a36Sopenharmony_ci		if (!epn)
35462306a36Sopenharmony_ci			return 0;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci		ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(epn),
35762306a36Sopenharmony_ci						 &v4l2_epn);
35862306a36Sopenharmony_ci		if (ret) {
35962306a36Sopenharmony_ci			ret = -EINVAL;
36062306a36Sopenharmony_ci			dev_err(dev, "Could not parse the endpoint\n");
36162306a36Sopenharmony_ci			break;
36262306a36Sopenharmony_ci		}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci		subdev_entity = devm_kzalloc(dev, sizeof(*subdev_entity),
36562306a36Sopenharmony_ci					     GFP_KERNEL);
36662306a36Sopenharmony_ci		if (!subdev_entity) {
36762306a36Sopenharmony_ci			ret = -ENOMEM;
36862306a36Sopenharmony_ci			break;
36962306a36Sopenharmony_ci		}
37062306a36Sopenharmony_ci		subdev_entity->epn = epn;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci		flags = v4l2_epn.bus.parallel.flags;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci		if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
37562306a36Sopenharmony_ci			subdev_entity->pfe_cfg0 = ISC_PFE_CFG0_HPOL_LOW;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci		if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
37862306a36Sopenharmony_ci			subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_VPOL_LOW;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci		if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
38162306a36Sopenharmony_ci			subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_PPOL_LOW;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci		if (v4l2_epn.bus_type == V4L2_MBUS_BT656)
38462306a36Sopenharmony_ci			subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_CCIR_CRC |
38562306a36Sopenharmony_ci					ISC_PFE_CFG0_CCIR656;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci		if (mipi_mode)
38862306a36Sopenharmony_ci			subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_MIPI;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci		list_add_tail(&subdev_entity->list, &isc->subdev_entities);
39162306a36Sopenharmony_ci	}
39262306a36Sopenharmony_ci	of_node_put(epn);
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	return ret;
39562306a36Sopenharmony_ci}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_cistatic int microchip_xisc_probe(struct platform_device *pdev)
39862306a36Sopenharmony_ci{
39962306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
40062306a36Sopenharmony_ci	struct isc_device *isc;
40162306a36Sopenharmony_ci	void __iomem *io_base;
40262306a36Sopenharmony_ci	struct isc_subdev_entity *subdev_entity;
40362306a36Sopenharmony_ci	int irq;
40462306a36Sopenharmony_ci	int ret;
40562306a36Sopenharmony_ci	u32 ver;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	isc = devm_kzalloc(dev, sizeof(*isc), GFP_KERNEL);
40862306a36Sopenharmony_ci	if (!isc)
40962306a36Sopenharmony_ci		return -ENOMEM;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	platform_set_drvdata(pdev, isc);
41262306a36Sopenharmony_ci	isc->dev = dev;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	io_base = devm_platform_ioremap_resource(pdev, 0);
41562306a36Sopenharmony_ci	if (IS_ERR(io_base))
41662306a36Sopenharmony_ci		return PTR_ERR(io_base);
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	isc->regmap = devm_regmap_init_mmio(dev, io_base, &microchip_isc_regmap_config);
41962306a36Sopenharmony_ci	if (IS_ERR(isc->regmap)) {
42062306a36Sopenharmony_ci		ret = PTR_ERR(isc->regmap);
42162306a36Sopenharmony_ci		dev_err(dev, "failed to init register map: %d\n", ret);
42262306a36Sopenharmony_ci		return ret;
42362306a36Sopenharmony_ci	}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
42662306a36Sopenharmony_ci	if (irq < 0)
42762306a36Sopenharmony_ci		return irq;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	ret = devm_request_irq(dev, irq, microchip_isc_interrupt, 0,
43062306a36Sopenharmony_ci			       "microchip-sama7g5-xisc", isc);
43162306a36Sopenharmony_ci	if (ret < 0) {
43262306a36Sopenharmony_ci		dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
43362306a36Sopenharmony_ci			irq, ret);
43462306a36Sopenharmony_ci		return ret;
43562306a36Sopenharmony_ci	}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	isc->gamma_table = isc_sama7g5_gamma_table;
43862306a36Sopenharmony_ci	isc->gamma_max = 0;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	isc->max_width = ISC_SAMA7G5_MAX_SUPPORT_WIDTH;
44162306a36Sopenharmony_ci	isc->max_height = ISC_SAMA7G5_MAX_SUPPORT_HEIGHT;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	isc->config_dpc = isc_sama7g5_config_dpc;
44462306a36Sopenharmony_ci	isc->config_csc = isc_sama7g5_config_csc;
44562306a36Sopenharmony_ci	isc->config_cbc = isc_sama7g5_config_cbc;
44662306a36Sopenharmony_ci	isc->config_cc = isc_sama7g5_config_cc;
44762306a36Sopenharmony_ci	isc->config_gam = isc_sama7g5_config_gam;
44862306a36Sopenharmony_ci	isc->config_rlp = isc_sama7g5_config_rlp;
44962306a36Sopenharmony_ci	isc->config_ctrls = isc_sama7g5_config_ctrls;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	isc->adapt_pipeline = isc_sama7g5_adapt_pipeline;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	isc->offsets.csc = ISC_SAMA7G5_CSC_OFFSET;
45462306a36Sopenharmony_ci	isc->offsets.cbc = ISC_SAMA7G5_CBC_OFFSET;
45562306a36Sopenharmony_ci	isc->offsets.sub422 = ISC_SAMA7G5_SUB422_OFFSET;
45662306a36Sopenharmony_ci	isc->offsets.sub420 = ISC_SAMA7G5_SUB420_OFFSET;
45762306a36Sopenharmony_ci	isc->offsets.rlp = ISC_SAMA7G5_RLP_OFFSET;
45862306a36Sopenharmony_ci	isc->offsets.his = ISC_SAMA7G5_HIS_OFFSET;
45962306a36Sopenharmony_ci	isc->offsets.dma = ISC_SAMA7G5_DMA_OFFSET;
46062306a36Sopenharmony_ci	isc->offsets.version = ISC_SAMA7G5_VERSION_OFFSET;
46162306a36Sopenharmony_ci	isc->offsets.his_entry = ISC_SAMA7G5_HIS_ENTRY_OFFSET;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	isc->controller_formats = sama7g5_controller_formats;
46462306a36Sopenharmony_ci	isc->controller_formats_size = ARRAY_SIZE(sama7g5_controller_formats);
46562306a36Sopenharmony_ci	isc->formats_list = sama7g5_formats_list;
46662306a36Sopenharmony_ci	isc->formats_list_size = ARRAY_SIZE(sama7g5_formats_list);
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	/* sama7g5-isc RAM access port is full AXI4 - 32 bits per beat */
46962306a36Sopenharmony_ci	isc->dcfg = ISC_DCFG_YMBSIZE_BEATS32 | ISC_DCFG_CMBSIZE_BEATS32;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	/* sama7g5-isc : ISPCK does not exist, ISC is clocked by MCK */
47262306a36Sopenharmony_ci	isc->ispck_required = false;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	ret = microchip_isc_pipeline_init(isc);
47562306a36Sopenharmony_ci	if (ret)
47662306a36Sopenharmony_ci		return ret;
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	isc->hclock = devm_clk_get(dev, "hclock");
47962306a36Sopenharmony_ci	if (IS_ERR(isc->hclock)) {
48062306a36Sopenharmony_ci		ret = PTR_ERR(isc->hclock);
48162306a36Sopenharmony_ci		dev_err(dev, "failed to get hclock: %d\n", ret);
48262306a36Sopenharmony_ci		return ret;
48362306a36Sopenharmony_ci	}
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	ret = clk_prepare_enable(isc->hclock);
48662306a36Sopenharmony_ci	if (ret) {
48762306a36Sopenharmony_ci		dev_err(dev, "failed to enable hclock: %d\n", ret);
48862306a36Sopenharmony_ci		return ret;
48962306a36Sopenharmony_ci	}
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	ret = microchip_isc_clk_init(isc);
49262306a36Sopenharmony_ci	if (ret) {
49362306a36Sopenharmony_ci		dev_err(dev, "failed to init isc clock: %d\n", ret);
49462306a36Sopenharmony_ci		goto unprepare_hclk;
49562306a36Sopenharmony_ci	}
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	ret = v4l2_device_register(dev, &isc->v4l2_dev);
49862306a36Sopenharmony_ci	if (ret) {
49962306a36Sopenharmony_ci		dev_err(dev, "unable to register v4l2 device.\n");
50062306a36Sopenharmony_ci		goto unprepare_hclk;
50162306a36Sopenharmony_ci	}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	ret = xisc_parse_dt(dev, isc);
50462306a36Sopenharmony_ci	if (ret) {
50562306a36Sopenharmony_ci		dev_err(dev, "fail to parse device tree\n");
50662306a36Sopenharmony_ci		goto unregister_v4l2_device;
50762306a36Sopenharmony_ci	}
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	if (list_empty(&isc->subdev_entities)) {
51062306a36Sopenharmony_ci		dev_err(dev, "no subdev found\n");
51162306a36Sopenharmony_ci		ret = -ENODEV;
51262306a36Sopenharmony_ci		goto unregister_v4l2_device;
51362306a36Sopenharmony_ci	}
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
51662306a36Sopenharmony_ci		struct v4l2_async_connection *asd;
51762306a36Sopenharmony_ci		struct fwnode_handle *fwnode =
51862306a36Sopenharmony_ci			of_fwnode_handle(subdev_entity->epn);
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci		v4l2_async_nf_init(&subdev_entity->notifier, &isc->v4l2_dev);
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci		asd = v4l2_async_nf_add_fwnode_remote(&subdev_entity->notifier,
52362306a36Sopenharmony_ci						      fwnode,
52462306a36Sopenharmony_ci						      struct v4l2_async_connection);
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci		of_node_put(subdev_entity->epn);
52762306a36Sopenharmony_ci		subdev_entity->epn = NULL;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci		if (IS_ERR(asd)) {
53062306a36Sopenharmony_ci			ret = PTR_ERR(asd);
53162306a36Sopenharmony_ci			goto cleanup_subdev;
53262306a36Sopenharmony_ci		}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci		subdev_entity->notifier.ops = &microchip_isc_async_ops;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci		ret = v4l2_async_nf_register(&subdev_entity->notifier);
53762306a36Sopenharmony_ci		if (ret) {
53862306a36Sopenharmony_ci			dev_err(dev, "fail to register async notifier\n");
53962306a36Sopenharmony_ci			goto cleanup_subdev;
54062306a36Sopenharmony_ci		}
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci		if (video_is_registered(&isc->video_dev))
54362306a36Sopenharmony_ci			break;
54462306a36Sopenharmony_ci	}
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	regmap_read(isc->regmap, ISC_VERSION + isc->offsets.version, &ver);
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	ret = isc_mc_init(isc, ver);
54962306a36Sopenharmony_ci	if (ret < 0)
55062306a36Sopenharmony_ci		goto isc_probe_mc_init_err;
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	pm_runtime_set_active(dev);
55362306a36Sopenharmony_ci	pm_runtime_enable(dev);
55462306a36Sopenharmony_ci	pm_request_idle(dev);
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	dev_info(dev, "Microchip XISC version %x\n", ver);
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	return 0;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ciisc_probe_mc_init_err:
56162306a36Sopenharmony_ci	isc_mc_cleanup(isc);
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_cicleanup_subdev:
56462306a36Sopenharmony_ci	microchip_isc_subdev_cleanup(isc);
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ciunregister_v4l2_device:
56762306a36Sopenharmony_ci	v4l2_device_unregister(&isc->v4l2_dev);
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ciunprepare_hclk:
57062306a36Sopenharmony_ci	clk_disable_unprepare(isc->hclock);
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	microchip_isc_clk_cleanup(isc);
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	return ret;
57562306a36Sopenharmony_ci}
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_cistatic void microchip_xisc_remove(struct platform_device *pdev)
57862306a36Sopenharmony_ci{
57962306a36Sopenharmony_ci	struct isc_device *isc = platform_get_drvdata(pdev);
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	isc_mc_cleanup(isc);
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	microchip_isc_subdev_cleanup(isc);
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	v4l2_device_unregister(&isc->v4l2_dev);
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	clk_disable_unprepare(isc->hclock);
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	microchip_isc_clk_cleanup(isc);
59262306a36Sopenharmony_ci}
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_cistatic int __maybe_unused xisc_runtime_suspend(struct device *dev)
59562306a36Sopenharmony_ci{
59662306a36Sopenharmony_ci	struct isc_device *isc = dev_get_drvdata(dev);
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	clk_disable_unprepare(isc->hclock);
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	return 0;
60162306a36Sopenharmony_ci}
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_cistatic int __maybe_unused xisc_runtime_resume(struct device *dev)
60462306a36Sopenharmony_ci{
60562306a36Sopenharmony_ci	struct isc_device *isc = dev_get_drvdata(dev);
60662306a36Sopenharmony_ci	int ret;
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	ret = clk_prepare_enable(isc->hclock);
60962306a36Sopenharmony_ci	if (ret)
61062306a36Sopenharmony_ci		return ret;
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	return ret;
61362306a36Sopenharmony_ci}
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_cistatic const struct dev_pm_ops microchip_xisc_dev_pm_ops = {
61662306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(xisc_runtime_suspend, xisc_runtime_resume, NULL)
61762306a36Sopenharmony_ci};
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_OF)
62062306a36Sopenharmony_cistatic const struct of_device_id microchip_xisc_of_match[] = {
62162306a36Sopenharmony_ci	{ .compatible = "microchip,sama7g5-isc" },
62262306a36Sopenharmony_ci	{ }
62362306a36Sopenharmony_ci};
62462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, microchip_xisc_of_match);
62562306a36Sopenharmony_ci#endif
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_cistatic struct platform_driver microchip_xisc_driver = {
62862306a36Sopenharmony_ci	.probe	= microchip_xisc_probe,
62962306a36Sopenharmony_ci	.remove_new = microchip_xisc_remove,
63062306a36Sopenharmony_ci	.driver	= {
63162306a36Sopenharmony_ci		.name		= "microchip-sama7g5-xisc",
63262306a36Sopenharmony_ci		.pm		= &microchip_xisc_dev_pm_ops,
63362306a36Sopenharmony_ci		.of_match_table = of_match_ptr(microchip_xisc_of_match),
63462306a36Sopenharmony_ci	},
63562306a36Sopenharmony_ci};
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_cimodule_platform_driver(microchip_xisc_driver);
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ciMODULE_AUTHOR("Eugen Hristev <eugen.hristev@microchip.com>");
64062306a36Sopenharmony_ciMODULE_DESCRIPTION("The V4L2 driver for Microchip-XISC");
64162306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
642