191b4e487SEugen Hristev // SPDX-License-Identifier: GPL-2.0-only
291b4e487SEugen Hristev /*
391b4e487SEugen Hristev  * Microchip Image Sensor Controller (ISC) common driver base
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 #include <linux/delay.h>
1291b4e487SEugen Hristev #include <linux/interrupt.h>
1391b4e487SEugen Hristev #include <linux/math64.h>
1491b4e487SEugen Hristev #include <linux/module.h>
1591b4e487SEugen Hristev #include <linux/of.h>
1691b4e487SEugen Hristev #include <linux/of_graph.h>
1791b4e487SEugen Hristev #include <linux/platform_device.h>
1891b4e487SEugen Hristev #include <linux/pm_runtime.h>
1991b4e487SEugen Hristev #include <linux/regmap.h>
2091b4e487SEugen Hristev #include <linux/videodev2.h>
2191b4e487SEugen Hristev #include <linux/atmel-isc-media.h>
2291b4e487SEugen Hristev 
2391b4e487SEugen Hristev #include <media/v4l2-ctrls.h>
2491b4e487SEugen Hristev #include <media/v4l2-device.h>
2591b4e487SEugen Hristev #include <media/v4l2-event.h>
2691b4e487SEugen Hristev #include <media/v4l2-image-sizes.h>
2791b4e487SEugen Hristev #include <media/v4l2-ioctl.h>
2891b4e487SEugen Hristev #include <media/v4l2-fwnode.h>
2991b4e487SEugen Hristev #include <media/v4l2-subdev.h>
3091b4e487SEugen Hristev #include <media/videobuf2-dma-contig.h>
3191b4e487SEugen Hristev 
3291b4e487SEugen Hristev #include "microchip-isc-regs.h"
3391b4e487SEugen Hristev #include "microchip-isc.h"
3491b4e487SEugen Hristev 
3591b4e487SEugen Hristev #define ISC_IS_FORMAT_RAW(mbus_code) \
3691b4e487SEugen Hristev 	(((mbus_code) & 0xf000) == 0x3000)
3791b4e487SEugen Hristev 
3891b4e487SEugen Hristev #define ISC_IS_FORMAT_GREY(mbus_code) \
3991b4e487SEugen Hristev 	(((mbus_code) == MEDIA_BUS_FMT_Y10_1X10) | \
4091b4e487SEugen Hristev 	(((mbus_code) == MEDIA_BUS_FMT_Y8_1X8)))
4191b4e487SEugen Hristev 
4291b4e487SEugen Hristev static inline void isc_update_v4l2_ctrls(struct isc_device *isc)
4391b4e487SEugen Hristev {
4491b4e487SEugen Hristev 	struct isc_ctrls *ctrls = &isc->ctrls;
4591b4e487SEugen Hristev 
4691b4e487SEugen Hristev 	/* In here we set the v4l2 controls w.r.t. our pipeline config */
4791b4e487SEugen Hristev 	v4l2_ctrl_s_ctrl(isc->r_gain_ctrl, ctrls->gain[ISC_HIS_CFG_MODE_R]);
4891b4e487SEugen Hristev 	v4l2_ctrl_s_ctrl(isc->b_gain_ctrl, ctrls->gain[ISC_HIS_CFG_MODE_B]);
4991b4e487SEugen Hristev 	v4l2_ctrl_s_ctrl(isc->gr_gain_ctrl, ctrls->gain[ISC_HIS_CFG_MODE_GR]);
5091b4e487SEugen Hristev 	v4l2_ctrl_s_ctrl(isc->gb_gain_ctrl, ctrls->gain[ISC_HIS_CFG_MODE_GB]);
5191b4e487SEugen Hristev 
5291b4e487SEugen Hristev 	v4l2_ctrl_s_ctrl(isc->r_off_ctrl, ctrls->offset[ISC_HIS_CFG_MODE_R]);
5391b4e487SEugen Hristev 	v4l2_ctrl_s_ctrl(isc->b_off_ctrl, ctrls->offset[ISC_HIS_CFG_MODE_B]);
5491b4e487SEugen Hristev 	v4l2_ctrl_s_ctrl(isc->gr_off_ctrl, ctrls->offset[ISC_HIS_CFG_MODE_GR]);
5591b4e487SEugen Hristev 	v4l2_ctrl_s_ctrl(isc->gb_off_ctrl, ctrls->offset[ISC_HIS_CFG_MODE_GB]);
5691b4e487SEugen Hristev }
5791b4e487SEugen Hristev 
5891b4e487SEugen Hristev static inline void isc_update_awb_ctrls(struct isc_device *isc)
5991b4e487SEugen Hristev {
6091b4e487SEugen Hristev 	struct isc_ctrls *ctrls = &isc->ctrls;
6191b4e487SEugen Hristev 
6291b4e487SEugen Hristev 	/* In here we set our actual hw pipeline config */
6391b4e487SEugen Hristev 
6491b4e487SEugen Hristev 	regmap_write(isc->regmap, ISC_WB_O_RGR,
6591b4e487SEugen Hristev 		     ((ctrls->offset[ISC_HIS_CFG_MODE_R])) |
6691b4e487SEugen Hristev 		     ((ctrls->offset[ISC_HIS_CFG_MODE_GR]) << 16));
6791b4e487SEugen Hristev 	regmap_write(isc->regmap, ISC_WB_O_BGB,
6891b4e487SEugen Hristev 		     ((ctrls->offset[ISC_HIS_CFG_MODE_B])) |
6991b4e487SEugen Hristev 		     ((ctrls->offset[ISC_HIS_CFG_MODE_GB]) << 16));
7091b4e487SEugen Hristev 	regmap_write(isc->regmap, ISC_WB_G_RGR,
7191b4e487SEugen Hristev 		     ctrls->gain[ISC_HIS_CFG_MODE_R] |
7291b4e487SEugen Hristev 		     (ctrls->gain[ISC_HIS_CFG_MODE_GR] << 16));
7391b4e487SEugen Hristev 	regmap_write(isc->regmap, ISC_WB_G_BGB,
7491b4e487SEugen Hristev 		     ctrls->gain[ISC_HIS_CFG_MODE_B] |
7591b4e487SEugen Hristev 		     (ctrls->gain[ISC_HIS_CFG_MODE_GB] << 16));
7691b4e487SEugen Hristev }
7791b4e487SEugen Hristev 
7891b4e487SEugen Hristev static inline void isc_reset_awb_ctrls(struct isc_device *isc)
7991b4e487SEugen Hristev {
8091b4e487SEugen Hristev 	unsigned int c;
8191b4e487SEugen Hristev 
8291b4e487SEugen Hristev 	for (c = ISC_HIS_CFG_MODE_GR; c <= ISC_HIS_CFG_MODE_B; c++) {
8391b4e487SEugen Hristev 		/* gains have a fixed point at 9 decimals */
8491b4e487SEugen Hristev 		isc->ctrls.gain[c] = 1 << 9;
8591b4e487SEugen Hristev 		/* offsets are in 2's complements */
8691b4e487SEugen Hristev 		isc->ctrls.offset[c] = 0;
8791b4e487SEugen Hristev 	}
8891b4e487SEugen Hristev }
8991b4e487SEugen Hristev 
9091b4e487SEugen Hristev static int isc_queue_setup(struct vb2_queue *vq,
9191b4e487SEugen Hristev 			   unsigned int *nbuffers, unsigned int *nplanes,
9291b4e487SEugen Hristev 			   unsigned int sizes[], struct device *alloc_devs[])
9391b4e487SEugen Hristev {
9491b4e487SEugen Hristev 	struct isc_device *isc = vb2_get_drv_priv(vq);
9591b4e487SEugen Hristev 	unsigned int size = isc->fmt.fmt.pix.sizeimage;
9691b4e487SEugen Hristev 
9791b4e487SEugen Hristev 	if (*nplanes)
9891b4e487SEugen Hristev 		return sizes[0] < size ? -EINVAL : 0;
9991b4e487SEugen Hristev 
10091b4e487SEugen Hristev 	*nplanes = 1;
10191b4e487SEugen Hristev 	sizes[0] = size;
10291b4e487SEugen Hristev 
10391b4e487SEugen Hristev 	return 0;
10491b4e487SEugen Hristev }
10591b4e487SEugen Hristev 
10691b4e487SEugen Hristev static int isc_buffer_prepare(struct vb2_buffer *vb)
10791b4e487SEugen Hristev {
10891b4e487SEugen Hristev 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
10991b4e487SEugen Hristev 	struct isc_device *isc = vb2_get_drv_priv(vb->vb2_queue);
11091b4e487SEugen Hristev 	unsigned long size = isc->fmt.fmt.pix.sizeimage;
11191b4e487SEugen Hristev 
11291b4e487SEugen Hristev 	if (vb2_plane_size(vb, 0) < size) {
113*8d46c5cdSEugen Hristev 		dev_err(isc->dev, "buffer too small (%lu < %lu)\n",
11491b4e487SEugen Hristev 			vb2_plane_size(vb, 0), size);
11591b4e487SEugen Hristev 		return -EINVAL;
11691b4e487SEugen Hristev 	}
11791b4e487SEugen Hristev 
11891b4e487SEugen Hristev 	vb2_set_plane_payload(vb, 0, size);
11991b4e487SEugen Hristev 
12091b4e487SEugen Hristev 	vbuf->field = isc->fmt.fmt.pix.field;
12191b4e487SEugen Hristev 
12291b4e487SEugen Hristev 	return 0;
12391b4e487SEugen Hristev }
12491b4e487SEugen Hristev 
12591b4e487SEugen Hristev static void isc_crop_pfe(struct isc_device *isc)
12691b4e487SEugen Hristev {
12791b4e487SEugen Hristev 	struct regmap *regmap = isc->regmap;
12891b4e487SEugen Hristev 	u32 h, w;
12991b4e487SEugen Hristev 
13091b4e487SEugen Hristev 	h = isc->fmt.fmt.pix.height;
13191b4e487SEugen Hristev 	w = isc->fmt.fmt.pix.width;
13291b4e487SEugen Hristev 
13391b4e487SEugen Hristev 	/*
13491b4e487SEugen Hristev 	 * In case the sensor is not RAW, it will output a pixel (12-16 bits)
13591b4e487SEugen Hristev 	 * with two samples on the ISC Data bus (which is 8-12)
13691b4e487SEugen Hristev 	 * ISC will count each sample, so, we need to multiply these values
13791b4e487SEugen Hristev 	 * by two, to get the real number of samples for the required pixels.
13891b4e487SEugen Hristev 	 */
13991b4e487SEugen Hristev 	if (!ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code)) {
14091b4e487SEugen Hristev 		h <<= 1;
14191b4e487SEugen Hristev 		w <<= 1;
14291b4e487SEugen Hristev 	}
14391b4e487SEugen Hristev 
14491b4e487SEugen Hristev 	/*
14591b4e487SEugen Hristev 	 * We limit the column/row count that the ISC will output according
14691b4e487SEugen Hristev 	 * to the configured resolution that we want.
14791b4e487SEugen Hristev 	 * This will avoid the situation where the sensor is misconfigured,
14891b4e487SEugen Hristev 	 * sending more data, and the ISC will just take it and DMA to memory,
14991b4e487SEugen Hristev 	 * causing corruption.
15091b4e487SEugen Hristev 	 */
15191b4e487SEugen Hristev 	regmap_write(regmap, ISC_PFE_CFG1,
15291b4e487SEugen Hristev 		     (ISC_PFE_CFG1_COLMIN(0) & ISC_PFE_CFG1_COLMIN_MASK) |
15391b4e487SEugen Hristev 		     (ISC_PFE_CFG1_COLMAX(w - 1) & ISC_PFE_CFG1_COLMAX_MASK));
15491b4e487SEugen Hristev 
15591b4e487SEugen Hristev 	regmap_write(regmap, ISC_PFE_CFG2,
15691b4e487SEugen Hristev 		     (ISC_PFE_CFG2_ROWMIN(0) & ISC_PFE_CFG2_ROWMIN_MASK) |
15791b4e487SEugen Hristev 		     (ISC_PFE_CFG2_ROWMAX(h - 1) & ISC_PFE_CFG2_ROWMAX_MASK));
15891b4e487SEugen Hristev 
15991b4e487SEugen Hristev 	regmap_update_bits(regmap, ISC_PFE_CFG0,
16091b4e487SEugen Hristev 			   ISC_PFE_CFG0_COLEN | ISC_PFE_CFG0_ROWEN,
16191b4e487SEugen Hristev 			   ISC_PFE_CFG0_COLEN | ISC_PFE_CFG0_ROWEN);
16291b4e487SEugen Hristev }
16391b4e487SEugen Hristev 
16491b4e487SEugen Hristev static void isc_start_dma(struct isc_device *isc)
16591b4e487SEugen Hristev {
16691b4e487SEugen Hristev 	struct regmap *regmap = isc->regmap;
16791b4e487SEugen Hristev 	u32 sizeimage = isc->fmt.fmt.pix.sizeimage;
16891b4e487SEugen Hristev 	u32 dctrl_dview;
16991b4e487SEugen Hristev 	dma_addr_t addr0;
17091b4e487SEugen Hristev 
17191b4e487SEugen Hristev 	addr0 = vb2_dma_contig_plane_dma_addr(&isc->cur_frm->vb.vb2_buf, 0);
17291b4e487SEugen Hristev 	regmap_write(regmap, ISC_DAD0 + isc->offsets.dma, addr0);
17391b4e487SEugen Hristev 
17491b4e487SEugen Hristev 	switch (isc->config.fourcc) {
17591b4e487SEugen Hristev 	case V4L2_PIX_FMT_YUV420:
17691b4e487SEugen Hristev 		regmap_write(regmap, ISC_DAD1 + isc->offsets.dma,
17791b4e487SEugen Hristev 			     addr0 + (sizeimage * 2) / 3);
17891b4e487SEugen Hristev 		regmap_write(regmap, ISC_DAD2 + isc->offsets.dma,
17991b4e487SEugen Hristev 			     addr0 + (sizeimage * 5) / 6);
18091b4e487SEugen Hristev 		break;
18191b4e487SEugen Hristev 	case V4L2_PIX_FMT_YUV422P:
18291b4e487SEugen Hristev 		regmap_write(regmap, ISC_DAD1 + isc->offsets.dma,
18391b4e487SEugen Hristev 			     addr0 + sizeimage / 2);
18491b4e487SEugen Hristev 		regmap_write(regmap, ISC_DAD2 + isc->offsets.dma,
18591b4e487SEugen Hristev 			     addr0 + (sizeimage * 3) / 4);
18691b4e487SEugen Hristev 		break;
18791b4e487SEugen Hristev 	default:
18891b4e487SEugen Hristev 		break;
18991b4e487SEugen Hristev 	}
19091b4e487SEugen Hristev 
19191b4e487SEugen Hristev 	dctrl_dview = isc->config.dctrl_dview;
19291b4e487SEugen Hristev 
19391b4e487SEugen Hristev 	regmap_write(regmap, ISC_DCTRL + isc->offsets.dma,
19491b4e487SEugen Hristev 		     dctrl_dview | ISC_DCTRL_IE_IS);
19591b4e487SEugen Hristev 	spin_lock(&isc->awb_lock);
19691b4e487SEugen Hristev 	regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_CAPTURE);
19791b4e487SEugen Hristev 	spin_unlock(&isc->awb_lock);
19891b4e487SEugen Hristev }
19991b4e487SEugen Hristev 
20091b4e487SEugen Hristev static void isc_set_pipeline(struct isc_device *isc, u32 pipeline)
20191b4e487SEugen Hristev {
20291b4e487SEugen Hristev 	struct regmap *regmap = isc->regmap;
20391b4e487SEugen Hristev 	struct isc_ctrls *ctrls = &isc->ctrls;
20491b4e487SEugen Hristev 	u32 val, bay_cfg;
20591b4e487SEugen Hristev 	const u32 *gamma;
20691b4e487SEugen Hristev 	unsigned int i;
20791b4e487SEugen Hristev 
20891b4e487SEugen Hristev 	/* WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB422-->SUB420 */
20991b4e487SEugen Hristev 	for (i = 0; i < ISC_PIPE_LINE_NODE_NUM; i++) {
21091b4e487SEugen Hristev 		val = pipeline & BIT(i) ? 1 : 0;
21191b4e487SEugen Hristev 		regmap_field_write(isc->pipeline[i], val);
21291b4e487SEugen Hristev 	}
21391b4e487SEugen Hristev 
21491b4e487SEugen Hristev 	if (!pipeline)
21591b4e487SEugen Hristev 		return;
21691b4e487SEugen Hristev 
21791b4e487SEugen Hristev 	bay_cfg = isc->config.sd_format->cfa_baycfg;
21891b4e487SEugen Hristev 
21991b4e487SEugen Hristev 	regmap_write(regmap, ISC_WB_CFG, bay_cfg);
22091b4e487SEugen Hristev 	isc_update_awb_ctrls(isc);
22191b4e487SEugen Hristev 	isc_update_v4l2_ctrls(isc);
22291b4e487SEugen Hristev 
22391b4e487SEugen Hristev 	regmap_write(regmap, ISC_CFA_CFG, bay_cfg | ISC_CFA_CFG_EITPOL);
22491b4e487SEugen Hristev 
22591b4e487SEugen Hristev 	gamma = &isc->gamma_table[ctrls->gamma_index][0];
22691b4e487SEugen Hristev 	regmap_bulk_write(regmap, ISC_GAM_BENTRY, gamma, GAMMA_ENTRIES);
22791b4e487SEugen Hristev 	regmap_bulk_write(regmap, ISC_GAM_GENTRY, gamma, GAMMA_ENTRIES);
22891b4e487SEugen Hristev 	regmap_bulk_write(regmap, ISC_GAM_RENTRY, gamma, GAMMA_ENTRIES);
22991b4e487SEugen Hristev 
23091b4e487SEugen Hristev 	isc->config_dpc(isc);
23191b4e487SEugen Hristev 	isc->config_csc(isc);
23291b4e487SEugen Hristev 	isc->config_cbc(isc);
23391b4e487SEugen Hristev 	isc->config_cc(isc);
23491b4e487SEugen Hristev 	isc->config_gam(isc);
23591b4e487SEugen Hristev }
23691b4e487SEugen Hristev 
23791b4e487SEugen Hristev static int isc_update_profile(struct isc_device *isc)
23891b4e487SEugen Hristev {
23991b4e487SEugen Hristev 	struct regmap *regmap = isc->regmap;
24091b4e487SEugen Hristev 	u32 sr;
24191b4e487SEugen Hristev 	int counter = 100;
24291b4e487SEugen Hristev 
24391b4e487SEugen Hristev 	regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_UPPRO);
24491b4e487SEugen Hristev 
24591b4e487SEugen Hristev 	regmap_read(regmap, ISC_CTRLSR, &sr);
24691b4e487SEugen Hristev 	while ((sr & ISC_CTRL_UPPRO) && counter--) {
24791b4e487SEugen Hristev 		usleep_range(1000, 2000);
24891b4e487SEugen Hristev 		regmap_read(regmap, ISC_CTRLSR, &sr);
24991b4e487SEugen Hristev 	}
25091b4e487SEugen Hristev 
25191b4e487SEugen Hristev 	if (counter < 0) {
25291b4e487SEugen Hristev 		v4l2_warn(&isc->v4l2_dev, "Time out to update profile\n");
25391b4e487SEugen Hristev 		return -ETIMEDOUT;
25491b4e487SEugen Hristev 	}
25591b4e487SEugen Hristev 
25691b4e487SEugen Hristev 	return 0;
25791b4e487SEugen Hristev }
25891b4e487SEugen Hristev 
25991b4e487SEugen Hristev static void isc_set_histogram(struct isc_device *isc, bool enable)
26091b4e487SEugen Hristev {
26191b4e487SEugen Hristev 	struct regmap *regmap = isc->regmap;
26291b4e487SEugen Hristev 	struct isc_ctrls *ctrls = &isc->ctrls;
26391b4e487SEugen Hristev 
26491b4e487SEugen Hristev 	if (enable) {
26591b4e487SEugen Hristev 		regmap_write(regmap, ISC_HIS_CFG + isc->offsets.his,
26691b4e487SEugen Hristev 			     ISC_HIS_CFG_MODE_GR |
26791b4e487SEugen Hristev 			     (isc->config.sd_format->cfa_baycfg
26891b4e487SEugen Hristev 					<< ISC_HIS_CFG_BAYSEL_SHIFT) |
26991b4e487SEugen Hristev 					ISC_HIS_CFG_RAR);
27091b4e487SEugen Hristev 		regmap_write(regmap, ISC_HIS_CTRL + isc->offsets.his,
27191b4e487SEugen Hristev 			     ISC_HIS_CTRL_EN);
27291b4e487SEugen Hristev 		regmap_write(regmap, ISC_INTEN, ISC_INT_HISDONE);
27391b4e487SEugen Hristev 		ctrls->hist_id = ISC_HIS_CFG_MODE_GR;
27491b4e487SEugen Hristev 		isc_update_profile(isc);
27591b4e487SEugen Hristev 		regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ);
27691b4e487SEugen Hristev 
27791b4e487SEugen Hristev 		ctrls->hist_stat = HIST_ENABLED;
27891b4e487SEugen Hristev 	} else {
27991b4e487SEugen Hristev 		regmap_write(regmap, ISC_INTDIS, ISC_INT_HISDONE);
28091b4e487SEugen Hristev 		regmap_write(regmap, ISC_HIS_CTRL + isc->offsets.his,
28191b4e487SEugen Hristev 			     ISC_HIS_CTRL_DIS);
28291b4e487SEugen Hristev 
28391b4e487SEugen Hristev 		ctrls->hist_stat = HIST_DISABLED;
28491b4e487SEugen Hristev 	}
28591b4e487SEugen Hristev }
28691b4e487SEugen Hristev 
28791b4e487SEugen Hristev static int isc_configure(struct isc_device *isc)
28891b4e487SEugen Hristev {
28991b4e487SEugen Hristev 	struct regmap *regmap = isc->regmap;
29091b4e487SEugen Hristev 	u32 pfe_cfg0, dcfg, mask, pipeline;
29191b4e487SEugen Hristev 	struct isc_subdev_entity *subdev = isc->current_subdev;
29291b4e487SEugen Hristev 
29391b4e487SEugen Hristev 	pfe_cfg0 = isc->config.sd_format->pfe_cfg0_bps;
29491b4e487SEugen Hristev 	pipeline = isc->config.bits_pipeline;
29591b4e487SEugen Hristev 
29691b4e487SEugen Hristev 	dcfg = isc->config.dcfg_imode | isc->dcfg;
29791b4e487SEugen Hristev 
29891b4e487SEugen Hristev 	pfe_cfg0  |= subdev->pfe_cfg0 | ISC_PFE_CFG0_MODE_PROGRESSIVE;
29991b4e487SEugen Hristev 	mask = ISC_PFE_CFG0_BPS_MASK | ISC_PFE_CFG0_HPOL_LOW |
30091b4e487SEugen Hristev 	       ISC_PFE_CFG0_VPOL_LOW | ISC_PFE_CFG0_PPOL_LOW |
30191b4e487SEugen Hristev 	       ISC_PFE_CFG0_MODE_MASK | ISC_PFE_CFG0_CCIR_CRC |
30291b4e487SEugen Hristev 	       ISC_PFE_CFG0_CCIR656 | ISC_PFE_CFG0_MIPI;
30391b4e487SEugen Hristev 
30491b4e487SEugen Hristev 	regmap_update_bits(regmap, ISC_PFE_CFG0, mask, pfe_cfg0);
30591b4e487SEugen Hristev 
30691b4e487SEugen Hristev 	isc->config_rlp(isc);
30791b4e487SEugen Hristev 
30891b4e487SEugen Hristev 	regmap_write(regmap, ISC_DCFG + isc->offsets.dma, dcfg);
30991b4e487SEugen Hristev 
31091b4e487SEugen Hristev 	/* Set the pipeline */
31191b4e487SEugen Hristev 	isc_set_pipeline(isc, pipeline);
31291b4e487SEugen Hristev 
31391b4e487SEugen Hristev 	/*
31491b4e487SEugen Hristev 	 * The current implemented histogram is available for RAW R, B, GB, GR
31591b4e487SEugen Hristev 	 * channels. We need to check if sensor is outputting RAW BAYER
31691b4e487SEugen Hristev 	 */
31791b4e487SEugen Hristev 	if (isc->ctrls.awb &&
31891b4e487SEugen Hristev 	    ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code))
31991b4e487SEugen Hristev 		isc_set_histogram(isc, true);
32091b4e487SEugen Hristev 	else
32191b4e487SEugen Hristev 		isc_set_histogram(isc, false);
32291b4e487SEugen Hristev 
32391b4e487SEugen Hristev 	/* Update profile */
32491b4e487SEugen Hristev 	return isc_update_profile(isc);
32591b4e487SEugen Hristev }
32691b4e487SEugen Hristev 
3278a8f9cedSEugen Hristev static int isc_prepare_streaming(struct vb2_queue *vq)
3288a8f9cedSEugen Hristev {
3298a8f9cedSEugen Hristev 	struct isc_device *isc = vb2_get_drv_priv(vq);
3308a8f9cedSEugen Hristev 
3318a8f9cedSEugen Hristev 	return media_pipeline_start(isc->video_dev.entity.pads, &isc->mpipe);
3328a8f9cedSEugen Hristev }
3338a8f9cedSEugen Hristev 
33491b4e487SEugen Hristev static int isc_start_streaming(struct vb2_queue *vq, unsigned int count)
33591b4e487SEugen Hristev {
33691b4e487SEugen Hristev 	struct isc_device *isc = vb2_get_drv_priv(vq);
33791b4e487SEugen Hristev 	struct regmap *regmap = isc->regmap;
33891b4e487SEugen Hristev 	struct isc_buffer *buf;
33991b4e487SEugen Hristev 	unsigned long flags;
34091b4e487SEugen Hristev 	int ret;
34191b4e487SEugen Hristev 
34291b4e487SEugen Hristev 	/* Enable stream on the sub device */
34391b4e487SEugen Hristev 	ret = v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 1);
34491b4e487SEugen Hristev 	if (ret && ret != -ENOIOCTLCMD) {
345*8d46c5cdSEugen Hristev 		dev_err(isc->dev, "stream on failed in subdev %d\n", ret);
34691b4e487SEugen Hristev 		goto err_start_stream;
34791b4e487SEugen Hristev 	}
34891b4e487SEugen Hristev 
34991b4e487SEugen Hristev 	ret = pm_runtime_resume_and_get(isc->dev);
35091b4e487SEugen Hristev 	if (ret < 0) {
351*8d46c5cdSEugen Hristev 		dev_err(isc->dev, "RPM resume failed in subdev %d\n",
35291b4e487SEugen Hristev 			ret);
35391b4e487SEugen Hristev 		goto err_pm_get;
35491b4e487SEugen Hristev 	}
35591b4e487SEugen Hristev 
35691b4e487SEugen Hristev 	ret = isc_configure(isc);
35791b4e487SEugen Hristev 	if (unlikely(ret))
35891b4e487SEugen Hristev 		goto err_configure;
35991b4e487SEugen Hristev 
36091b4e487SEugen Hristev 	/* Enable DMA interrupt */
36191b4e487SEugen Hristev 	regmap_write(regmap, ISC_INTEN, ISC_INT_DDONE);
36291b4e487SEugen Hristev 
36391b4e487SEugen Hristev 	spin_lock_irqsave(&isc->dma_queue_lock, flags);
36491b4e487SEugen Hristev 
36591b4e487SEugen Hristev 	isc->sequence = 0;
36691b4e487SEugen Hristev 	isc->stop = false;
36791b4e487SEugen Hristev 	reinit_completion(&isc->comp);
36891b4e487SEugen Hristev 
36991b4e487SEugen Hristev 	isc->cur_frm = list_first_entry(&isc->dma_queue,
37091b4e487SEugen Hristev 					struct isc_buffer, list);
37191b4e487SEugen Hristev 	list_del(&isc->cur_frm->list);
37291b4e487SEugen Hristev 
37391b4e487SEugen Hristev 	isc_crop_pfe(isc);
37491b4e487SEugen Hristev 	isc_start_dma(isc);
37591b4e487SEugen Hristev 
37691b4e487SEugen Hristev 	spin_unlock_irqrestore(&isc->dma_queue_lock, flags);
37791b4e487SEugen Hristev 
37891b4e487SEugen Hristev 	/* if we streaming from RAW, we can do one-shot white balance adj */
37991b4e487SEugen Hristev 	if (ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code))
38091b4e487SEugen Hristev 		v4l2_ctrl_activate(isc->do_wb_ctrl, true);
38191b4e487SEugen Hristev 
38291b4e487SEugen Hristev 	return 0;
38391b4e487SEugen Hristev 
38491b4e487SEugen Hristev err_configure:
38591b4e487SEugen Hristev 	pm_runtime_put_sync(isc->dev);
38691b4e487SEugen Hristev err_pm_get:
38791b4e487SEugen Hristev 	v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 0);
38891b4e487SEugen Hristev 
38991b4e487SEugen Hristev err_start_stream:
39091b4e487SEugen Hristev 	spin_lock_irqsave(&isc->dma_queue_lock, flags);
39191b4e487SEugen Hristev 	list_for_each_entry(buf, &isc->dma_queue, list)
39291b4e487SEugen Hristev 		vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED);
39391b4e487SEugen Hristev 	INIT_LIST_HEAD(&isc->dma_queue);
39491b4e487SEugen Hristev 	spin_unlock_irqrestore(&isc->dma_queue_lock, flags);
39591b4e487SEugen Hristev 
39691b4e487SEugen Hristev 	return ret;
39791b4e487SEugen Hristev }
39891b4e487SEugen Hristev 
3998a8f9cedSEugen Hristev static void isc_unprepare_streaming(struct vb2_queue *vq)
4008a8f9cedSEugen Hristev {
4018a8f9cedSEugen Hristev 	struct isc_device *isc = vb2_get_drv_priv(vq);
4028a8f9cedSEugen Hristev 
4038a8f9cedSEugen Hristev 	/* Stop media pipeline */
4048a8f9cedSEugen Hristev 	media_pipeline_stop(isc->video_dev.entity.pads);
4058a8f9cedSEugen Hristev }
4068a8f9cedSEugen Hristev 
40791b4e487SEugen Hristev static void isc_stop_streaming(struct vb2_queue *vq)
40891b4e487SEugen Hristev {
40991b4e487SEugen Hristev 	struct isc_device *isc = vb2_get_drv_priv(vq);
41091b4e487SEugen Hristev 	unsigned long flags;
41191b4e487SEugen Hristev 	struct isc_buffer *buf;
41291b4e487SEugen Hristev 	int ret;
41391b4e487SEugen Hristev 
41491b4e487SEugen Hristev 	mutex_lock(&isc->awb_mutex);
41591b4e487SEugen Hristev 	v4l2_ctrl_activate(isc->do_wb_ctrl, false);
41691b4e487SEugen Hristev 
41791b4e487SEugen Hristev 	isc->stop = true;
41891b4e487SEugen Hristev 
41991b4e487SEugen Hristev 	/* Wait until the end of the current frame */
42091b4e487SEugen Hristev 	if (isc->cur_frm && !wait_for_completion_timeout(&isc->comp, 5 * HZ))
421*8d46c5cdSEugen Hristev 		dev_err(isc->dev, "Timeout waiting for end of the capture\n");
42291b4e487SEugen Hristev 
42391b4e487SEugen Hristev 	mutex_unlock(&isc->awb_mutex);
42491b4e487SEugen Hristev 
42591b4e487SEugen Hristev 	/* Disable DMA interrupt */
42691b4e487SEugen Hristev 	regmap_write(isc->regmap, ISC_INTDIS, ISC_INT_DDONE);
42791b4e487SEugen Hristev 
42891b4e487SEugen Hristev 	pm_runtime_put_sync(isc->dev);
42991b4e487SEugen Hristev 
43091b4e487SEugen Hristev 	/* Disable stream on the sub device */
43191b4e487SEugen Hristev 	ret = v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 0);
43291b4e487SEugen Hristev 	if (ret && ret != -ENOIOCTLCMD)
433*8d46c5cdSEugen Hristev 		dev_err(isc->dev, "stream off failed in subdev\n");
43491b4e487SEugen Hristev 
43591b4e487SEugen Hristev 	/* Release all active buffers */
43691b4e487SEugen Hristev 	spin_lock_irqsave(&isc->dma_queue_lock, flags);
43791b4e487SEugen Hristev 	if (unlikely(isc->cur_frm)) {
43891b4e487SEugen Hristev 		vb2_buffer_done(&isc->cur_frm->vb.vb2_buf,
43991b4e487SEugen Hristev 				VB2_BUF_STATE_ERROR);
44091b4e487SEugen Hristev 		isc->cur_frm = NULL;
44191b4e487SEugen Hristev 	}
44291b4e487SEugen Hristev 	list_for_each_entry(buf, &isc->dma_queue, list)
44391b4e487SEugen Hristev 		vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
44491b4e487SEugen Hristev 	INIT_LIST_HEAD(&isc->dma_queue);
44591b4e487SEugen Hristev 	spin_unlock_irqrestore(&isc->dma_queue_lock, flags);
44691b4e487SEugen Hristev }
44791b4e487SEugen Hristev 
44891b4e487SEugen Hristev static void isc_buffer_queue(struct vb2_buffer *vb)
44991b4e487SEugen Hristev {
45091b4e487SEugen Hristev 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
45191b4e487SEugen Hristev 	struct isc_buffer *buf = container_of(vbuf, struct isc_buffer, vb);
45291b4e487SEugen Hristev 	struct isc_device *isc = vb2_get_drv_priv(vb->vb2_queue);
45391b4e487SEugen Hristev 	unsigned long flags;
45491b4e487SEugen Hristev 
45591b4e487SEugen Hristev 	spin_lock_irqsave(&isc->dma_queue_lock, flags);
45691b4e487SEugen Hristev 	if (!isc->cur_frm && list_empty(&isc->dma_queue) &&
45791b4e487SEugen Hristev 	    vb2_start_streaming_called(vb->vb2_queue)) {
45891b4e487SEugen Hristev 		isc->cur_frm = buf;
45991b4e487SEugen Hristev 		isc_start_dma(isc);
46091b4e487SEugen Hristev 	} else {
46191b4e487SEugen Hristev 		list_add_tail(&buf->list, &isc->dma_queue);
46291b4e487SEugen Hristev 	}
46391b4e487SEugen Hristev 	spin_unlock_irqrestore(&isc->dma_queue_lock, flags);
46491b4e487SEugen Hristev }
46591b4e487SEugen Hristev 
46691b4e487SEugen Hristev static const struct vb2_ops isc_vb2_ops = {
46791b4e487SEugen Hristev 	.queue_setup		= isc_queue_setup,
46891b4e487SEugen Hristev 	.wait_prepare		= vb2_ops_wait_prepare,
46991b4e487SEugen Hristev 	.wait_finish		= vb2_ops_wait_finish,
47091b4e487SEugen Hristev 	.buf_prepare		= isc_buffer_prepare,
47191b4e487SEugen Hristev 	.start_streaming	= isc_start_streaming,
47291b4e487SEugen Hristev 	.stop_streaming		= isc_stop_streaming,
47391b4e487SEugen Hristev 	.buf_queue		= isc_buffer_queue,
4748a8f9cedSEugen Hristev 	.prepare_streaming	= isc_prepare_streaming,
4758a8f9cedSEugen Hristev 	.unprepare_streaming	= isc_unprepare_streaming,
47691b4e487SEugen Hristev };
47791b4e487SEugen Hristev 
47891b4e487SEugen Hristev static int isc_querycap(struct file *file, void *priv,
47991b4e487SEugen Hristev 			struct v4l2_capability *cap)
48091b4e487SEugen Hristev {
48191b4e487SEugen Hristev 	struct isc_device *isc = video_drvdata(file);
48291b4e487SEugen Hristev 
48391b4e487SEugen Hristev 	strscpy(cap->driver, "microchip-isc", sizeof(cap->driver));
48491b4e487SEugen Hristev 	strscpy(cap->card, "Microchip Image Sensor Controller", sizeof(cap->card));
48591b4e487SEugen Hristev 	snprintf(cap->bus_info, sizeof(cap->bus_info),
48691b4e487SEugen Hristev 		 "platform:%s", isc->v4l2_dev.name);
48791b4e487SEugen Hristev 
48891b4e487SEugen Hristev 	return 0;
48991b4e487SEugen Hristev }
49091b4e487SEugen Hristev 
49191b4e487SEugen Hristev static int isc_enum_fmt_vid_cap(struct file *file, void *priv,
49291b4e487SEugen Hristev 				struct v4l2_fmtdesc *f)
49391b4e487SEugen Hristev {
49491b4e487SEugen Hristev 	struct isc_device *isc = video_drvdata(file);
49591b4e487SEugen Hristev 	u32 index = f->index;
49678ba0d79SEugen Hristev 	u32 i, supported_index = 0;
49778ba0d79SEugen Hristev 	struct isc_format *fmt;
49891b4e487SEugen Hristev 
49978ba0d79SEugen Hristev 	/*
50078ba0d79SEugen Hristev 	 * If we are not asked a specific mbus_code, we have to report all
50178ba0d79SEugen Hristev 	 * the formats that we can output.
50278ba0d79SEugen Hristev 	 */
50378ba0d79SEugen Hristev 	if (!f->mbus_code) {
50478ba0d79SEugen Hristev 		if (index >= isc->controller_formats_size)
50578ba0d79SEugen Hristev 			return -EINVAL;
50678ba0d79SEugen Hristev 
50791b4e487SEugen Hristev 		f->pixelformat = isc->controller_formats[index].fourcc;
50878ba0d79SEugen Hristev 
50991b4e487SEugen Hristev 		return 0;
51091b4e487SEugen Hristev 	}
51191b4e487SEugen Hristev 
51278ba0d79SEugen Hristev 	/*
51378ba0d79SEugen Hristev 	 * If a specific mbus_code is requested, check if we support
51478ba0d79SEugen Hristev 	 * this mbus_code as input for the ISC.
51578ba0d79SEugen Hristev 	 * If it's supported, then we report the corresponding pixelformat
51678ba0d79SEugen Hristev 	 * as first possible option for the ISC.
51778ba0d79SEugen Hristev 	 * E.g. mbus MEDIA_BUS_FMT_YUYV8_2X8 and report
51878ba0d79SEugen Hristev 	 * 'YUYV' (YUYV 4:2:2)
51978ba0d79SEugen Hristev 	 */
52078ba0d79SEugen Hristev 	fmt = isc_find_format_by_code(isc, f->mbus_code, &i);
52178ba0d79SEugen Hristev 	if (!fmt)
52278ba0d79SEugen Hristev 		return -EINVAL;
52391b4e487SEugen Hristev 
52478ba0d79SEugen Hristev 	if (!index) {
52578ba0d79SEugen Hristev 		f->pixelformat = fmt->fourcc;
52691b4e487SEugen Hristev 
52778ba0d79SEugen Hristev 		return 0;
52878ba0d79SEugen Hristev 	}
52978ba0d79SEugen Hristev 
53078ba0d79SEugen Hristev 	supported_index++;
53178ba0d79SEugen Hristev 
53278ba0d79SEugen Hristev 	/* If the index is not raw, we don't have anymore formats to report */
53378ba0d79SEugen Hristev 	if (!ISC_IS_FORMAT_RAW(f->mbus_code))
53478ba0d79SEugen Hristev 		return -EINVAL;
53578ba0d79SEugen Hristev 
53678ba0d79SEugen Hristev 	/*
53778ba0d79SEugen Hristev 	 * We are asked for a specific mbus code, which is raw.
53878ba0d79SEugen Hristev 	 * We have to search through the formats we can convert to.
53978ba0d79SEugen Hristev 	 * We have to skip the raw formats, we cannot convert to raw.
54078ba0d79SEugen Hristev 	 * E.g. 'AR12' (16-bit ARGB 4-4-4-4), 'AR15' (16-bit ARGB 1-5-5-5), etc.
54178ba0d79SEugen Hristev 	 */
54278ba0d79SEugen Hristev 	for (i = 0; i < isc->controller_formats_size; i++) {
54378ba0d79SEugen Hristev 		if (isc->controller_formats[i].raw)
54491b4e487SEugen Hristev 			continue;
54578ba0d79SEugen Hristev 		if (index == supported_index) {
54678ba0d79SEugen Hristev 			f->pixelformat = isc->controller_formats[i].fourcc;
54791b4e487SEugen Hristev 			return 0;
54891b4e487SEugen Hristev 		}
54991b4e487SEugen Hristev 		supported_index++;
55091b4e487SEugen Hristev 	}
55191b4e487SEugen Hristev 
55291b4e487SEugen Hristev 	return -EINVAL;
55391b4e487SEugen Hristev }
55491b4e487SEugen Hristev 
55591b4e487SEugen Hristev static int isc_g_fmt_vid_cap(struct file *file, void *priv,
55691b4e487SEugen Hristev 			     struct v4l2_format *fmt)
55791b4e487SEugen Hristev {
55891b4e487SEugen Hristev 	struct isc_device *isc = video_drvdata(file);
55991b4e487SEugen Hristev 
56091b4e487SEugen Hristev 	*fmt = isc->fmt;
56191b4e487SEugen Hristev 
56291b4e487SEugen Hristev 	return 0;
56391b4e487SEugen Hristev }
56491b4e487SEugen Hristev 
56591b4e487SEugen Hristev /*
56691b4e487SEugen Hristev  * Checks the current configured format, if ISC can output it,
56791b4e487SEugen Hristev  * considering which type of format the ISC receives from the sensor
56891b4e487SEugen Hristev  */
56991b4e487SEugen Hristev static int isc_try_validate_formats(struct isc_device *isc)
57091b4e487SEugen Hristev {
57191b4e487SEugen Hristev 	int ret;
57291b4e487SEugen Hristev 	bool bayer = false, yuv = false, rgb = false, grey = false;
57391b4e487SEugen Hristev 
57491b4e487SEugen Hristev 	/* all formats supported by the RLP module are OK */
57591b4e487SEugen Hristev 	switch (isc->try_config.fourcc) {
57691b4e487SEugen Hristev 	case V4L2_PIX_FMT_SBGGR8:
57791b4e487SEugen Hristev 	case V4L2_PIX_FMT_SGBRG8:
57891b4e487SEugen Hristev 	case V4L2_PIX_FMT_SGRBG8:
57991b4e487SEugen Hristev 	case V4L2_PIX_FMT_SRGGB8:
58091b4e487SEugen Hristev 	case V4L2_PIX_FMT_SBGGR10:
58191b4e487SEugen Hristev 	case V4L2_PIX_FMT_SGBRG10:
58291b4e487SEugen Hristev 	case V4L2_PIX_FMT_SGRBG10:
58391b4e487SEugen Hristev 	case V4L2_PIX_FMT_SRGGB10:
58491b4e487SEugen Hristev 	case V4L2_PIX_FMT_SBGGR12:
58591b4e487SEugen Hristev 	case V4L2_PIX_FMT_SGBRG12:
58691b4e487SEugen Hristev 	case V4L2_PIX_FMT_SGRBG12:
58791b4e487SEugen Hristev 	case V4L2_PIX_FMT_SRGGB12:
58891b4e487SEugen Hristev 		ret = 0;
58991b4e487SEugen Hristev 		bayer = true;
59091b4e487SEugen Hristev 		break;
59191b4e487SEugen Hristev 
59291b4e487SEugen Hristev 	case V4L2_PIX_FMT_YUV420:
59391b4e487SEugen Hristev 	case V4L2_PIX_FMT_YUV422P:
59491b4e487SEugen Hristev 	case V4L2_PIX_FMT_YUYV:
59591b4e487SEugen Hristev 	case V4L2_PIX_FMT_UYVY:
59691b4e487SEugen Hristev 	case V4L2_PIX_FMT_VYUY:
59791b4e487SEugen Hristev 		ret = 0;
59891b4e487SEugen Hristev 		yuv = true;
59991b4e487SEugen Hristev 		break;
60091b4e487SEugen Hristev 
60191b4e487SEugen Hristev 	case V4L2_PIX_FMT_RGB565:
60291b4e487SEugen Hristev 	case V4L2_PIX_FMT_ABGR32:
60391b4e487SEugen Hristev 	case V4L2_PIX_FMT_XBGR32:
60491b4e487SEugen Hristev 	case V4L2_PIX_FMT_ARGB444:
60591b4e487SEugen Hristev 	case V4L2_PIX_FMT_ARGB555:
60691b4e487SEugen Hristev 		ret = 0;
60791b4e487SEugen Hristev 		rgb = true;
60891b4e487SEugen Hristev 		break;
60991b4e487SEugen Hristev 	case V4L2_PIX_FMT_GREY:
61091b4e487SEugen Hristev 	case V4L2_PIX_FMT_Y10:
61191b4e487SEugen Hristev 	case V4L2_PIX_FMT_Y16:
61291b4e487SEugen Hristev 		ret = 0;
61391b4e487SEugen Hristev 		grey = true;
61491b4e487SEugen Hristev 		break;
61591b4e487SEugen Hristev 	default:
61691b4e487SEugen Hristev 	/* any other different formats are not supported */
617*8d46c5cdSEugen Hristev 		dev_err(isc->dev, "Requested unsupported format.\n");
61891b4e487SEugen Hristev 		ret = -EINVAL;
61991b4e487SEugen Hristev 	}
620*8d46c5cdSEugen Hristev 	dev_dbg(isc->dev,
62191b4e487SEugen Hristev 		"Format validation, requested rgb=%u, yuv=%u, grey=%u, bayer=%u\n",
62291b4e487SEugen Hristev 		rgb, yuv, grey, bayer);
62391b4e487SEugen Hristev 
62478ba0d79SEugen Hristev 	if (bayer &&
62578ba0d79SEugen Hristev 	    !ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
626*8d46c5cdSEugen Hristev 		dev_err(isc->dev, "Cannot output RAW if we do not receive RAW.\n");
62791b4e487SEugen Hristev 		return -EINVAL;
62878ba0d79SEugen Hristev 	}
62991b4e487SEugen Hristev 
63091b4e487SEugen Hristev 	if (grey && !ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code) &&
63178ba0d79SEugen Hristev 	    !ISC_IS_FORMAT_GREY(isc->try_config.sd_format->mbus_code)) {
632*8d46c5cdSEugen Hristev 		dev_err(isc->dev, "Cannot output GREY if we do not receive RAW/GREY.\n");
63391b4e487SEugen Hristev 		return -EINVAL;
63478ba0d79SEugen Hristev 	}
63578ba0d79SEugen Hristev 
63678ba0d79SEugen Hristev 	if ((rgb || bayer || yuv) &&
63778ba0d79SEugen Hristev 	    ISC_IS_FORMAT_GREY(isc->try_config.sd_format->mbus_code)) {
638*8d46c5cdSEugen Hristev 		dev_err(isc->dev, "Cannot convert GREY to another format.\n");
63978ba0d79SEugen Hristev 		return -EINVAL;
64078ba0d79SEugen Hristev 	}
64191b4e487SEugen Hristev 
64291b4e487SEugen Hristev 	return ret;
64391b4e487SEugen Hristev }
64491b4e487SEugen Hristev 
64591b4e487SEugen Hristev /*
64691b4e487SEugen Hristev  * Configures the RLP and DMA modules, depending on the output format
64791b4e487SEugen Hristev  * configured for the ISC.
64891b4e487SEugen Hristev  * If direct_dump == true, just dump raw data 8/16 bits depending on format.
64991b4e487SEugen Hristev  */
65091b4e487SEugen Hristev static int isc_try_configure_rlp_dma(struct isc_device *isc, bool direct_dump)
65191b4e487SEugen Hristev {
65291b4e487SEugen Hristev 	isc->try_config.rlp_cfg_mode = 0;
65391b4e487SEugen Hristev 
65491b4e487SEugen Hristev 	switch (isc->try_config.fourcc) {
65591b4e487SEugen Hristev 	case V4L2_PIX_FMT_SBGGR8:
65691b4e487SEugen Hristev 	case V4L2_PIX_FMT_SGBRG8:
65791b4e487SEugen Hristev 	case V4L2_PIX_FMT_SGRBG8:
65891b4e487SEugen Hristev 	case V4L2_PIX_FMT_SRGGB8:
65991b4e487SEugen Hristev 		isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8;
66091b4e487SEugen Hristev 		isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED8;
66191b4e487SEugen Hristev 		isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
66291b4e487SEugen Hristev 		isc->try_config.bpp = 8;
66391b4e487SEugen Hristev 		isc->try_config.bpp_v4l2 = 8;
66491b4e487SEugen Hristev 		break;
66591b4e487SEugen Hristev 	case V4L2_PIX_FMT_SBGGR10:
66691b4e487SEugen Hristev 	case V4L2_PIX_FMT_SGBRG10:
66791b4e487SEugen Hristev 	case V4L2_PIX_FMT_SGRBG10:
66891b4e487SEugen Hristev 	case V4L2_PIX_FMT_SRGGB10:
66991b4e487SEugen Hristev 		isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT10;
67091b4e487SEugen Hristev 		isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16;
67191b4e487SEugen Hristev 		isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
67291b4e487SEugen Hristev 		isc->try_config.bpp = 16;
67391b4e487SEugen Hristev 		isc->try_config.bpp_v4l2 = 16;
67491b4e487SEugen Hristev 		break;
67591b4e487SEugen Hristev 	case V4L2_PIX_FMT_SBGGR12:
67691b4e487SEugen Hristev 	case V4L2_PIX_FMT_SGBRG12:
67791b4e487SEugen Hristev 	case V4L2_PIX_FMT_SGRBG12:
67891b4e487SEugen Hristev 	case V4L2_PIX_FMT_SRGGB12:
67991b4e487SEugen Hristev 		isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT12;
68091b4e487SEugen Hristev 		isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16;
68191b4e487SEugen Hristev 		isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
68291b4e487SEugen Hristev 		isc->try_config.bpp = 16;
68391b4e487SEugen Hristev 		isc->try_config.bpp_v4l2 = 16;
68491b4e487SEugen Hristev 		break;
68591b4e487SEugen Hristev 	case V4L2_PIX_FMT_RGB565:
68691b4e487SEugen Hristev 		isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_RGB565;
68791b4e487SEugen Hristev 		isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16;
68891b4e487SEugen Hristev 		isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
68991b4e487SEugen Hristev 		isc->try_config.bpp = 16;
69091b4e487SEugen Hristev 		isc->try_config.bpp_v4l2 = 16;
69191b4e487SEugen Hristev 		break;
69291b4e487SEugen Hristev 	case V4L2_PIX_FMT_ARGB444:
69391b4e487SEugen Hristev 		isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB444;
69491b4e487SEugen Hristev 		isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16;
69591b4e487SEugen Hristev 		isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
69691b4e487SEugen Hristev 		isc->try_config.bpp = 16;
69791b4e487SEugen Hristev 		isc->try_config.bpp_v4l2 = 16;
69891b4e487SEugen Hristev 		break;
69991b4e487SEugen Hristev 	case V4L2_PIX_FMT_ARGB555:
70091b4e487SEugen Hristev 		isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB555;
70191b4e487SEugen Hristev 		isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16;
70291b4e487SEugen Hristev 		isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
70391b4e487SEugen Hristev 		isc->try_config.bpp = 16;
70491b4e487SEugen Hristev 		isc->try_config.bpp_v4l2 = 16;
70591b4e487SEugen Hristev 		break;
70691b4e487SEugen Hristev 	case V4L2_PIX_FMT_ABGR32:
70791b4e487SEugen Hristev 	case V4L2_PIX_FMT_XBGR32:
70891b4e487SEugen Hristev 		isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB32;
70991b4e487SEugen Hristev 		isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED32;
71091b4e487SEugen Hristev 		isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
71191b4e487SEugen Hristev 		isc->try_config.bpp = 32;
71291b4e487SEugen Hristev 		isc->try_config.bpp_v4l2 = 32;
71391b4e487SEugen Hristev 		break;
71491b4e487SEugen Hristev 	case V4L2_PIX_FMT_YUV420:
71591b4e487SEugen Hristev 		isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC;
71691b4e487SEugen Hristev 		isc->try_config.dcfg_imode = ISC_DCFG_IMODE_YC420P;
71791b4e487SEugen Hristev 		isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PLANAR;
71891b4e487SEugen Hristev 		isc->try_config.bpp = 12;
71991b4e487SEugen Hristev 		isc->try_config.bpp_v4l2 = 8; /* only first plane */
72091b4e487SEugen Hristev 		break;
72191b4e487SEugen Hristev 	case V4L2_PIX_FMT_YUV422P:
72291b4e487SEugen Hristev 		isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC;
72391b4e487SEugen Hristev 		isc->try_config.dcfg_imode = ISC_DCFG_IMODE_YC422P;
72491b4e487SEugen Hristev 		isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PLANAR;
72591b4e487SEugen Hristev 		isc->try_config.bpp = 16;
72691b4e487SEugen Hristev 		isc->try_config.bpp_v4l2 = 8; /* only first plane */
72791b4e487SEugen Hristev 		break;
72891b4e487SEugen Hristev 	case V4L2_PIX_FMT_YUYV:
72991b4e487SEugen Hristev 		isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YCYC | ISC_RLP_CFG_YMODE_YUYV;
73091b4e487SEugen Hristev 		isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED32;
73191b4e487SEugen Hristev 		isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
73291b4e487SEugen Hristev 		isc->try_config.bpp = 16;
73391b4e487SEugen Hristev 		isc->try_config.bpp_v4l2 = 16;
73491b4e487SEugen Hristev 		break;
73591b4e487SEugen Hristev 	case V4L2_PIX_FMT_UYVY:
73691b4e487SEugen Hristev 		isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YCYC | ISC_RLP_CFG_YMODE_UYVY;
73791b4e487SEugen Hristev 		isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED32;
73891b4e487SEugen Hristev 		isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
73991b4e487SEugen Hristev 		isc->try_config.bpp = 16;
74091b4e487SEugen Hristev 		isc->try_config.bpp_v4l2 = 16;
74191b4e487SEugen Hristev 		break;
74291b4e487SEugen Hristev 	case V4L2_PIX_FMT_VYUY:
74391b4e487SEugen Hristev 		isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YCYC | ISC_RLP_CFG_YMODE_VYUY;
74491b4e487SEugen Hristev 		isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED32;
74591b4e487SEugen Hristev 		isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
74691b4e487SEugen Hristev 		isc->try_config.bpp = 16;
74791b4e487SEugen Hristev 		isc->try_config.bpp_v4l2 = 16;
74891b4e487SEugen Hristev 		break;
74991b4e487SEugen Hristev 	case V4L2_PIX_FMT_GREY:
75091b4e487SEugen Hristev 		isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DATY8;
75191b4e487SEugen Hristev 		isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED8;
75291b4e487SEugen Hristev 		isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
75391b4e487SEugen Hristev 		isc->try_config.bpp = 8;
75491b4e487SEugen Hristev 		isc->try_config.bpp_v4l2 = 8;
75591b4e487SEugen Hristev 		break;
75691b4e487SEugen Hristev 	case V4L2_PIX_FMT_Y16:
75791b4e487SEugen Hristev 		isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DATY10 | ISC_RLP_CFG_LSH;
75891b4e487SEugen Hristev 		fallthrough;
75991b4e487SEugen Hristev 	case V4L2_PIX_FMT_Y10:
76091b4e487SEugen Hristev 		isc->try_config.rlp_cfg_mode |= ISC_RLP_CFG_MODE_DATY10;
76191b4e487SEugen Hristev 		isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16;
76291b4e487SEugen Hristev 		isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
76391b4e487SEugen Hristev 		isc->try_config.bpp = 16;
76491b4e487SEugen Hristev 		isc->try_config.bpp_v4l2 = 16;
76591b4e487SEugen Hristev 		break;
76691b4e487SEugen Hristev 	default:
76791b4e487SEugen Hristev 		return -EINVAL;
76891b4e487SEugen Hristev 	}
76991b4e487SEugen Hristev 
77091b4e487SEugen Hristev 	if (direct_dump) {
77191b4e487SEugen Hristev 		isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8;
77291b4e487SEugen Hristev 		isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED8;
77391b4e487SEugen Hristev 		isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
77491b4e487SEugen Hristev 		return 0;
77591b4e487SEugen Hristev 	}
77691b4e487SEugen Hristev 
77791b4e487SEugen Hristev 	return 0;
77891b4e487SEugen Hristev }
77991b4e487SEugen Hristev 
78091b4e487SEugen Hristev /*
78191b4e487SEugen Hristev  * Configuring pipeline modules, depending on which format the ISC outputs
78291b4e487SEugen Hristev  * and considering which format it has as input from the sensor.
78391b4e487SEugen Hristev  */
78491b4e487SEugen Hristev static int isc_try_configure_pipeline(struct isc_device *isc)
78591b4e487SEugen Hristev {
78691b4e487SEugen Hristev 	switch (isc->try_config.fourcc) {
78791b4e487SEugen Hristev 	case V4L2_PIX_FMT_RGB565:
78891b4e487SEugen Hristev 	case V4L2_PIX_FMT_ARGB555:
78991b4e487SEugen Hristev 	case V4L2_PIX_FMT_ARGB444:
79091b4e487SEugen Hristev 	case V4L2_PIX_FMT_ABGR32:
79191b4e487SEugen Hristev 	case V4L2_PIX_FMT_XBGR32:
79291b4e487SEugen Hristev 		/* if sensor format is RAW, we convert inside ISC */
79391b4e487SEugen Hristev 		if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
79491b4e487SEugen Hristev 			isc->try_config.bits_pipeline = CFA_ENABLE |
79591b4e487SEugen Hristev 				WB_ENABLE | GAM_ENABLES | DPC_BLCENABLE |
79691b4e487SEugen Hristev 				CC_ENABLE;
79791b4e487SEugen Hristev 		} else {
79891b4e487SEugen Hristev 			isc->try_config.bits_pipeline = 0x0;
79991b4e487SEugen Hristev 		}
80091b4e487SEugen Hristev 		break;
80191b4e487SEugen Hristev 	case V4L2_PIX_FMT_YUV420:
80291b4e487SEugen Hristev 		/* if sensor format is RAW, we convert inside ISC */
80391b4e487SEugen Hristev 		if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
80491b4e487SEugen Hristev 			isc->try_config.bits_pipeline = CFA_ENABLE |
80591b4e487SEugen Hristev 				CSC_ENABLE | GAM_ENABLES | WB_ENABLE |
80691b4e487SEugen Hristev 				SUB420_ENABLE | SUB422_ENABLE | CBC_ENABLE |
80791b4e487SEugen Hristev 				DPC_BLCENABLE;
80891b4e487SEugen Hristev 		} else {
80991b4e487SEugen Hristev 			isc->try_config.bits_pipeline = 0x0;
81091b4e487SEugen Hristev 		}
81191b4e487SEugen Hristev 		break;
81291b4e487SEugen Hristev 	case V4L2_PIX_FMT_YUV422P:
81391b4e487SEugen Hristev 		/* if sensor format is RAW, we convert inside ISC */
81491b4e487SEugen Hristev 		if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
81591b4e487SEugen Hristev 			isc->try_config.bits_pipeline = CFA_ENABLE |
81691b4e487SEugen Hristev 				CSC_ENABLE | WB_ENABLE | GAM_ENABLES |
81791b4e487SEugen Hristev 				SUB422_ENABLE | CBC_ENABLE | DPC_BLCENABLE;
81891b4e487SEugen Hristev 		} else {
81991b4e487SEugen Hristev 			isc->try_config.bits_pipeline = 0x0;
82091b4e487SEugen Hristev 		}
82191b4e487SEugen Hristev 		break;
82291b4e487SEugen Hristev 	case V4L2_PIX_FMT_YUYV:
82391b4e487SEugen Hristev 	case V4L2_PIX_FMT_UYVY:
82491b4e487SEugen Hristev 	case V4L2_PIX_FMT_VYUY:
82591b4e487SEugen Hristev 		/* if sensor format is RAW, we convert inside ISC */
82691b4e487SEugen Hristev 		if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
82791b4e487SEugen Hristev 			isc->try_config.bits_pipeline = CFA_ENABLE |
82891b4e487SEugen Hristev 				CSC_ENABLE | WB_ENABLE | GAM_ENABLES |
82991b4e487SEugen Hristev 				SUB422_ENABLE | CBC_ENABLE | DPC_BLCENABLE;
83091b4e487SEugen Hristev 		} else {
83191b4e487SEugen Hristev 			isc->try_config.bits_pipeline = 0x0;
83291b4e487SEugen Hristev 		}
83391b4e487SEugen Hristev 		break;
83491b4e487SEugen Hristev 	case V4L2_PIX_FMT_GREY:
83591b4e487SEugen Hristev 	case V4L2_PIX_FMT_Y16:
83691b4e487SEugen Hristev 		/* if sensor format is RAW, we convert inside ISC */
83791b4e487SEugen Hristev 		if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
83891b4e487SEugen Hristev 			isc->try_config.bits_pipeline = CFA_ENABLE |
83991b4e487SEugen Hristev 				CSC_ENABLE | WB_ENABLE | GAM_ENABLES |
84091b4e487SEugen Hristev 				CBC_ENABLE | DPC_BLCENABLE;
84191b4e487SEugen Hristev 		} else {
84291b4e487SEugen Hristev 			isc->try_config.bits_pipeline = 0x0;
84391b4e487SEugen Hristev 		}
84491b4e487SEugen Hristev 		break;
84591b4e487SEugen Hristev 	default:
84691b4e487SEugen Hristev 		if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code))
84791b4e487SEugen Hristev 			isc->try_config.bits_pipeline = WB_ENABLE | DPC_BLCENABLE;
84891b4e487SEugen Hristev 		else
84991b4e487SEugen Hristev 			isc->try_config.bits_pipeline = 0x0;
85091b4e487SEugen Hristev 	}
85191b4e487SEugen Hristev 
85291b4e487SEugen Hristev 	/* Tune the pipeline to product specific */
85391b4e487SEugen Hristev 	isc->adapt_pipeline(isc);
85491b4e487SEugen Hristev 
85591b4e487SEugen Hristev 	return 0;
85691b4e487SEugen Hristev }
85791b4e487SEugen Hristev 
85891b4e487SEugen Hristev static void isc_try_fse(struct isc_device *isc,
85991b4e487SEugen Hristev 			struct v4l2_subdev_state *sd_state)
86091b4e487SEugen Hristev {
86191b4e487SEugen Hristev 	int ret;
86291b4e487SEugen Hristev 	struct v4l2_subdev_frame_size_enum fse = {};
86391b4e487SEugen Hristev 
86491b4e487SEugen Hristev 	/*
86591b4e487SEugen Hristev 	 * If we do not know yet which format the subdev is using, we cannot
86691b4e487SEugen Hristev 	 * do anything.
86791b4e487SEugen Hristev 	 */
86878ba0d79SEugen Hristev 	if (!isc->config.sd_format)
86991b4e487SEugen Hristev 		return;
87091b4e487SEugen Hristev 
87191b4e487SEugen Hristev 	fse.code = isc->try_config.sd_format->mbus_code;
87291b4e487SEugen Hristev 	fse.which = V4L2_SUBDEV_FORMAT_TRY;
87391b4e487SEugen Hristev 
87491b4e487SEugen Hristev 	ret = v4l2_subdev_call(isc->current_subdev->sd, pad, enum_frame_size,
87591b4e487SEugen Hristev 			       sd_state, &fse);
87691b4e487SEugen Hristev 	/*
87791b4e487SEugen Hristev 	 * Attempt to obtain format size from subdev. If not available,
87891b4e487SEugen Hristev 	 * just use the maximum ISC can receive.
87991b4e487SEugen Hristev 	 */
88091b4e487SEugen Hristev 	if (ret) {
88191b4e487SEugen Hristev 		sd_state->pads->try_crop.width = isc->max_width;
88291b4e487SEugen Hristev 		sd_state->pads->try_crop.height = isc->max_height;
88391b4e487SEugen Hristev 	} else {
88491b4e487SEugen Hristev 		sd_state->pads->try_crop.width = fse.max_width;
88591b4e487SEugen Hristev 		sd_state->pads->try_crop.height = fse.max_height;
88691b4e487SEugen Hristev 	}
88791b4e487SEugen Hristev }
88891b4e487SEugen Hristev 
88978ba0d79SEugen Hristev static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f)
89091b4e487SEugen Hristev {
89191b4e487SEugen Hristev 	struct v4l2_pix_format *pixfmt = &f->fmt.pix;
89278ba0d79SEugen Hristev 	unsigned int i;
89391b4e487SEugen Hristev 
89491b4e487SEugen Hristev 	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
89591b4e487SEugen Hristev 		return -EINVAL;
89691b4e487SEugen Hristev 
89778ba0d79SEugen Hristev 	isc->try_config.fourcc = isc->controller_formats[0].fourcc;
89878ba0d79SEugen Hristev 
89978ba0d79SEugen Hristev 	/* find if the format requested is supported */
90078ba0d79SEugen Hristev 	for (i = 0; i < isc->controller_formats_size; i++)
90178ba0d79SEugen Hristev 		if (isc->controller_formats[i].fourcc == pixfmt->pixelformat) {
90278ba0d79SEugen Hristev 			isc->try_config.fourcc = pixfmt->pixelformat;
90391b4e487SEugen Hristev 			break;
90491b4e487SEugen Hristev 		}
90591b4e487SEugen Hristev 
90678ba0d79SEugen Hristev 	isc_try_configure_rlp_dma(isc, false);
90791b4e487SEugen Hristev 
90891b4e487SEugen Hristev 	/* Limit to Microchip ISC hardware capabilities */
90978ba0d79SEugen Hristev 	v4l_bound_align_image(&pixfmt->width, 16, isc->max_width, 0,
91078ba0d79SEugen Hristev 			      &pixfmt->height, 16, isc->max_height, 0, 0);
91178ba0d79SEugen Hristev 	/* If we did not find the requested format, we will fallback here */
91278ba0d79SEugen Hristev 	pixfmt->pixelformat = isc->try_config.fourcc;
91378ba0d79SEugen Hristev 	pixfmt->colorspace = V4L2_COLORSPACE_SRGB;
91491b4e487SEugen Hristev 	pixfmt->field = V4L2_FIELD_NONE;
91578ba0d79SEugen Hristev 
91691b4e487SEugen Hristev 	pixfmt->bytesperline = (pixfmt->width * isc->try_config.bpp_v4l2) >> 3;
91791b4e487SEugen Hristev 	pixfmt->sizeimage = ((pixfmt->width * isc->try_config.bpp) >> 3) *
91891b4e487SEugen Hristev 			     pixfmt->height;
91991b4e487SEugen Hristev 
92078ba0d79SEugen Hristev 	isc->try_fmt = *f;
92191b4e487SEugen Hristev 
92291b4e487SEugen Hristev 	return 0;
92391b4e487SEugen Hristev }
92491b4e487SEugen Hristev 
92591b4e487SEugen Hristev static int isc_set_fmt(struct isc_device *isc, struct v4l2_format *f)
92691b4e487SEugen Hristev {
92778ba0d79SEugen Hristev 	isc_try_fmt(isc, f);
92878ba0d79SEugen Hristev 
92978ba0d79SEugen Hristev 	/* make the try configuration active */
93078ba0d79SEugen Hristev 	isc->config = isc->try_config;
93178ba0d79SEugen Hristev 	isc->fmt = isc->try_fmt;
93278ba0d79SEugen Hristev 
933*8d46c5cdSEugen Hristev 	dev_dbg(isc->dev, "ISC set_fmt to %.4s @%dx%d\n",
93478ba0d79SEugen Hristev 		(char *)&f->fmt.pix.pixelformat,
93578ba0d79SEugen Hristev 		f->fmt.pix.width, f->fmt.pix.height);
93678ba0d79SEugen Hristev 
93778ba0d79SEugen Hristev 	return 0;
93878ba0d79SEugen Hristev }
93978ba0d79SEugen Hristev 
94078ba0d79SEugen Hristev static int isc_validate(struct isc_device *isc)
94178ba0d79SEugen Hristev {
94278ba0d79SEugen Hristev 	int ret;
94378ba0d79SEugen Hristev 	int i;
94478ba0d79SEugen Hristev 	struct isc_format *sd_fmt = NULL;
94578ba0d79SEugen Hristev 	struct v4l2_pix_format *pixfmt = &isc->fmt.fmt.pix;
94691b4e487SEugen Hristev 	struct v4l2_subdev_format format = {
94791b4e487SEugen Hristev 		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
94878ba0d79SEugen Hristev 		.pad = isc->remote_pad,
94991b4e487SEugen Hristev 	};
95078ba0d79SEugen Hristev 	struct v4l2_subdev_pad_config pad_cfg = {};
95178ba0d79SEugen Hristev 	struct v4l2_subdev_state pad_state = {
95278ba0d79SEugen Hristev 		.pads = &pad_cfg,
95378ba0d79SEugen Hristev 	};
95491b4e487SEugen Hristev 
95578ba0d79SEugen Hristev 	/* Get current format from subdev */
95678ba0d79SEugen Hristev 	ret = v4l2_subdev_call(isc->current_subdev->sd, pad, get_fmt, NULL,
95778ba0d79SEugen Hristev 			       &format);
95891b4e487SEugen Hristev 	if (ret)
95991b4e487SEugen Hristev 		return ret;
96091b4e487SEugen Hristev 
96178ba0d79SEugen Hristev 	/* Identify the subdev's format configuration */
96278ba0d79SEugen Hristev 	for (i = 0; i < isc->formats_list_size; i++)
96378ba0d79SEugen Hristev 		if (isc->formats_list[i].mbus_code == format.format.code) {
96478ba0d79SEugen Hristev 			sd_fmt = &isc->formats_list[i];
96578ba0d79SEugen Hristev 			break;
96678ba0d79SEugen Hristev 		}
96778ba0d79SEugen Hristev 
96878ba0d79SEugen Hristev 	/* Check if the format is not supported */
96978ba0d79SEugen Hristev 	if (!sd_fmt) {
970*8d46c5cdSEugen Hristev 		dev_err(isc->dev,
97178ba0d79SEugen Hristev 			"Current subdevice is streaming a media bus code that is not supported 0x%x\n",
97278ba0d79SEugen Hristev 			format.format.code);
97378ba0d79SEugen Hristev 		return -EPIPE;
97478ba0d79SEugen Hristev 	}
97578ba0d79SEugen Hristev 
97678ba0d79SEugen Hristev 	/* At this moment we know which format the subdev will use */
97778ba0d79SEugen Hristev 	isc->try_config.sd_format = sd_fmt;
97878ba0d79SEugen Hristev 
97978ba0d79SEugen Hristev 	/* If the sensor is not RAW, we can only do a direct dump */
98078ba0d79SEugen Hristev 	if (!ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code))
98178ba0d79SEugen Hristev 		isc_try_configure_rlp_dma(isc, true);
98291b4e487SEugen Hristev 
98391b4e487SEugen Hristev 	/* Limit to Microchip ISC hardware capabilities */
98478ba0d79SEugen Hristev 	v4l_bound_align_image(&format.format.width, 16, isc->max_width, 0,
98578ba0d79SEugen Hristev 			      &format.format.height, 16, isc->max_height, 0, 0);
98691b4e487SEugen Hristev 
98778ba0d79SEugen Hristev 	/* Check if the frame size is the same. Otherwise we may overflow */
98878ba0d79SEugen Hristev 	if (pixfmt->height != format.format.height ||
98978ba0d79SEugen Hristev 	    pixfmt->width != format.format.width) {
990*8d46c5cdSEugen Hristev 		dev_err(isc->dev,
99178ba0d79SEugen Hristev 			"ISC not configured with the proper frame size: %dx%d\n",
99278ba0d79SEugen Hristev 			format.format.width, format.format.height);
99378ba0d79SEugen Hristev 		return -EPIPE;
99478ba0d79SEugen Hristev 	}
99591b4e487SEugen Hristev 
996*8d46c5cdSEugen Hristev 	dev_dbg(isc->dev,
99778ba0d79SEugen Hristev 		"Identified subdev using format %.4s with %dx%d %d bpp\n",
99878ba0d79SEugen Hristev 		(char *)&sd_fmt->fourcc, pixfmt->width, pixfmt->height,
99978ba0d79SEugen Hristev 		isc->try_config.bpp);
100078ba0d79SEugen Hristev 
100178ba0d79SEugen Hristev 	/* Reset and restart AWB if the subdevice changed the format */
100291b4e487SEugen Hristev 	if (isc->try_config.sd_format && isc->config.sd_format &&
100391b4e487SEugen Hristev 	    isc->try_config.sd_format != isc->config.sd_format) {
100491b4e487SEugen Hristev 		isc->ctrls.hist_stat = HIST_INIT;
100591b4e487SEugen Hristev 		isc_reset_awb_ctrls(isc);
100691b4e487SEugen Hristev 		isc_update_v4l2_ctrls(isc);
100791b4e487SEugen Hristev 	}
100878ba0d79SEugen Hristev 
100978ba0d79SEugen Hristev 	/* Validate formats */
101078ba0d79SEugen Hristev 	ret = isc_try_validate_formats(isc);
101178ba0d79SEugen Hristev 	if (ret)
101278ba0d79SEugen Hristev 		return ret;
101378ba0d79SEugen Hristev 
101478ba0d79SEugen Hristev 	/* Obtain frame sizes if possible to have crop requirements ready */
101578ba0d79SEugen Hristev 	isc_try_fse(isc, &pad_state);
101678ba0d79SEugen Hristev 
101778ba0d79SEugen Hristev 	/* Configure ISC pipeline for the config */
101878ba0d79SEugen Hristev 	ret = isc_try_configure_pipeline(isc);
101978ba0d79SEugen Hristev 	if (ret)
102078ba0d79SEugen Hristev 		return ret;
102178ba0d79SEugen Hristev 
102291b4e487SEugen Hristev 	isc->config = isc->try_config;
102391b4e487SEugen Hristev 
1024*8d46c5cdSEugen Hristev 	dev_dbg(isc->dev, "New ISC configuration in place\n");
102591b4e487SEugen Hristev 
102691b4e487SEugen Hristev 	return 0;
102791b4e487SEugen Hristev }
102891b4e487SEugen Hristev 
102991b4e487SEugen Hristev static int isc_s_fmt_vid_cap(struct file *file, void *priv,
103091b4e487SEugen Hristev 			     struct v4l2_format *f)
103191b4e487SEugen Hristev {
103291b4e487SEugen Hristev 	struct isc_device *isc = video_drvdata(file);
103391b4e487SEugen Hristev 
103491b4e487SEugen Hristev 	if (vb2_is_busy(&isc->vb2_vidq))
103591b4e487SEugen Hristev 		return -EBUSY;
103691b4e487SEugen Hristev 
103791b4e487SEugen Hristev 	return isc_set_fmt(isc, f);
103891b4e487SEugen Hristev }
103991b4e487SEugen Hristev 
104091b4e487SEugen Hristev static int isc_try_fmt_vid_cap(struct file *file, void *priv,
104191b4e487SEugen Hristev 			       struct v4l2_format *f)
104291b4e487SEugen Hristev {
104391b4e487SEugen Hristev 	struct isc_device *isc = video_drvdata(file);
104491b4e487SEugen Hristev 
104578ba0d79SEugen Hristev 	return isc_try_fmt(isc, f);
104691b4e487SEugen Hristev }
104791b4e487SEugen Hristev 
104891b4e487SEugen Hristev static int isc_enum_input(struct file *file, void *priv,
104991b4e487SEugen Hristev 			  struct v4l2_input *inp)
105091b4e487SEugen Hristev {
105191b4e487SEugen Hristev 	if (inp->index != 0)
105291b4e487SEugen Hristev 		return -EINVAL;
105391b4e487SEugen Hristev 
105491b4e487SEugen Hristev 	inp->type = V4L2_INPUT_TYPE_CAMERA;
105591b4e487SEugen Hristev 	inp->std = 0;
105691b4e487SEugen Hristev 	strscpy(inp->name, "Camera", sizeof(inp->name));
105791b4e487SEugen Hristev 
105891b4e487SEugen Hristev 	return 0;
105991b4e487SEugen Hristev }
106091b4e487SEugen Hristev 
106191b4e487SEugen Hristev static int isc_g_input(struct file *file, void *priv, unsigned int *i)
106291b4e487SEugen Hristev {
106391b4e487SEugen Hristev 	*i = 0;
106491b4e487SEugen Hristev 
106591b4e487SEugen Hristev 	return 0;
106691b4e487SEugen Hristev }
106791b4e487SEugen Hristev 
106891b4e487SEugen Hristev static int isc_s_input(struct file *file, void *priv, unsigned int i)
106991b4e487SEugen Hristev {
107091b4e487SEugen Hristev 	if (i > 0)
107191b4e487SEugen Hristev 		return -EINVAL;
107291b4e487SEugen Hristev 
107391b4e487SEugen Hristev 	return 0;
107491b4e487SEugen Hristev }
107591b4e487SEugen Hristev 
107691b4e487SEugen Hristev static int isc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
107791b4e487SEugen Hristev {
107891b4e487SEugen Hristev 	struct isc_device *isc = video_drvdata(file);
107991b4e487SEugen Hristev 
108091b4e487SEugen Hristev 	return v4l2_g_parm_cap(video_devdata(file), isc->current_subdev->sd, a);
108191b4e487SEugen Hristev }
108291b4e487SEugen Hristev 
108391b4e487SEugen Hristev static int isc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
108491b4e487SEugen Hristev {
108591b4e487SEugen Hristev 	struct isc_device *isc = video_drvdata(file);
108691b4e487SEugen Hristev 
108791b4e487SEugen Hristev 	return v4l2_s_parm_cap(video_devdata(file), isc->current_subdev->sd, a);
108891b4e487SEugen Hristev }
108991b4e487SEugen Hristev 
109091b4e487SEugen Hristev static int isc_enum_framesizes(struct file *file, void *fh,
109191b4e487SEugen Hristev 			       struct v4l2_frmsizeenum *fsize)
109291b4e487SEugen Hristev {
109391b4e487SEugen Hristev 	struct isc_device *isc = video_drvdata(file);
109491b4e487SEugen Hristev 	int ret = -EINVAL;
109591b4e487SEugen Hristev 	int i;
109691b4e487SEugen Hristev 
109791b4e487SEugen Hristev 	if (fsize->index)
109891b4e487SEugen Hristev 		return -EINVAL;
109991b4e487SEugen Hristev 
110091b4e487SEugen Hristev 	for (i = 0; i < isc->controller_formats_size; i++)
110191b4e487SEugen Hristev 		if (isc->controller_formats[i].fourcc == fsize->pixel_format)
110291b4e487SEugen Hristev 			ret = 0;
110391b4e487SEugen Hristev 
110491b4e487SEugen Hristev 	if (ret)
110591b4e487SEugen Hristev 		return ret;
110691b4e487SEugen Hristev 
110791b4e487SEugen Hristev 	fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
110891b4e487SEugen Hristev 
110991b4e487SEugen Hristev 	fsize->stepwise.min_width = 16;
111091b4e487SEugen Hristev 	fsize->stepwise.max_width = isc->max_width;
111191b4e487SEugen Hristev 	fsize->stepwise.min_height = 16;
111291b4e487SEugen Hristev 	fsize->stepwise.max_height = isc->max_height;
111391b4e487SEugen Hristev 	fsize->stepwise.step_width = 1;
111491b4e487SEugen Hristev 	fsize->stepwise.step_height = 1;
111591b4e487SEugen Hristev 
111691b4e487SEugen Hristev 	return 0;
111791b4e487SEugen Hristev }
111891b4e487SEugen Hristev 
111991b4e487SEugen Hristev static const struct v4l2_ioctl_ops isc_ioctl_ops = {
112091b4e487SEugen Hristev 	.vidioc_querycap		= isc_querycap,
112191b4e487SEugen Hristev 	.vidioc_enum_fmt_vid_cap	= isc_enum_fmt_vid_cap,
112291b4e487SEugen Hristev 	.vidioc_g_fmt_vid_cap		= isc_g_fmt_vid_cap,
112391b4e487SEugen Hristev 	.vidioc_s_fmt_vid_cap		= isc_s_fmt_vid_cap,
112491b4e487SEugen Hristev 	.vidioc_try_fmt_vid_cap		= isc_try_fmt_vid_cap,
112591b4e487SEugen Hristev 
112691b4e487SEugen Hristev 	.vidioc_enum_input		= isc_enum_input,
112791b4e487SEugen Hristev 	.vidioc_g_input			= isc_g_input,
112891b4e487SEugen Hristev 	.vidioc_s_input			= isc_s_input,
112991b4e487SEugen Hristev 
113091b4e487SEugen Hristev 	.vidioc_reqbufs			= vb2_ioctl_reqbufs,
113191b4e487SEugen Hristev 	.vidioc_querybuf		= vb2_ioctl_querybuf,
113291b4e487SEugen Hristev 	.vidioc_qbuf			= vb2_ioctl_qbuf,
113391b4e487SEugen Hristev 	.vidioc_expbuf			= vb2_ioctl_expbuf,
113491b4e487SEugen Hristev 	.vidioc_dqbuf			= vb2_ioctl_dqbuf,
113591b4e487SEugen Hristev 	.vidioc_create_bufs		= vb2_ioctl_create_bufs,
113691b4e487SEugen Hristev 	.vidioc_prepare_buf		= vb2_ioctl_prepare_buf,
113791b4e487SEugen Hristev 	.vidioc_streamon		= vb2_ioctl_streamon,
113891b4e487SEugen Hristev 	.vidioc_streamoff		= vb2_ioctl_streamoff,
113991b4e487SEugen Hristev 
114091b4e487SEugen Hristev 	.vidioc_g_parm			= isc_g_parm,
114191b4e487SEugen Hristev 	.vidioc_s_parm			= isc_s_parm,
114291b4e487SEugen Hristev 	.vidioc_enum_framesizes		= isc_enum_framesizes,
114391b4e487SEugen Hristev 
114491b4e487SEugen Hristev 	.vidioc_log_status		= v4l2_ctrl_log_status,
114591b4e487SEugen Hristev 	.vidioc_subscribe_event		= v4l2_ctrl_subscribe_event,
114691b4e487SEugen Hristev 	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
114791b4e487SEugen Hristev };
114891b4e487SEugen Hristev 
114991b4e487SEugen Hristev static int isc_open(struct file *file)
115091b4e487SEugen Hristev {
115191b4e487SEugen Hristev 	struct isc_device *isc = video_drvdata(file);
115291b4e487SEugen Hristev 	struct v4l2_subdev *sd = isc->current_subdev->sd;
115391b4e487SEugen Hristev 	int ret;
115491b4e487SEugen Hristev 
115591b4e487SEugen Hristev 	if (mutex_lock_interruptible(&isc->lock))
115691b4e487SEugen Hristev 		return -ERESTARTSYS;
115791b4e487SEugen Hristev 
115891b4e487SEugen Hristev 	ret = v4l2_fh_open(file);
115991b4e487SEugen Hristev 	if (ret < 0)
116091b4e487SEugen Hristev 		goto unlock;
116191b4e487SEugen Hristev 
116291b4e487SEugen Hristev 	if (!v4l2_fh_is_singular_file(file))
116391b4e487SEugen Hristev 		goto unlock;
116491b4e487SEugen Hristev 
116591b4e487SEugen Hristev 	ret = v4l2_subdev_call(sd, core, s_power, 1);
116691b4e487SEugen Hristev 	if (ret < 0 && ret != -ENOIOCTLCMD) {
116791b4e487SEugen Hristev 		v4l2_fh_release(file);
116891b4e487SEugen Hristev 		goto unlock;
116991b4e487SEugen Hristev 	}
117091b4e487SEugen Hristev 
117191b4e487SEugen Hristev 	ret = isc_set_fmt(isc, &isc->fmt);
117291b4e487SEugen Hristev 	if (ret) {
117391b4e487SEugen Hristev 		v4l2_subdev_call(sd, core, s_power, 0);
117491b4e487SEugen Hristev 		v4l2_fh_release(file);
117591b4e487SEugen Hristev 	}
117691b4e487SEugen Hristev 
117791b4e487SEugen Hristev unlock:
117891b4e487SEugen Hristev 	mutex_unlock(&isc->lock);
117991b4e487SEugen Hristev 	return ret;
118091b4e487SEugen Hristev }
118191b4e487SEugen Hristev 
118291b4e487SEugen Hristev static int isc_release(struct file *file)
118391b4e487SEugen Hristev {
118491b4e487SEugen Hristev 	struct isc_device *isc = video_drvdata(file);
118591b4e487SEugen Hristev 	struct v4l2_subdev *sd = isc->current_subdev->sd;
118691b4e487SEugen Hristev 	bool fh_singular;
118791b4e487SEugen Hristev 	int ret;
118891b4e487SEugen Hristev 
118991b4e487SEugen Hristev 	mutex_lock(&isc->lock);
119091b4e487SEugen Hristev 
119191b4e487SEugen Hristev 	fh_singular = v4l2_fh_is_singular_file(file);
119291b4e487SEugen Hristev 
119391b4e487SEugen Hristev 	ret = _vb2_fop_release(file, NULL);
119491b4e487SEugen Hristev 
119591b4e487SEugen Hristev 	if (fh_singular)
119691b4e487SEugen Hristev 		v4l2_subdev_call(sd, core, s_power, 0);
119791b4e487SEugen Hristev 
119891b4e487SEugen Hristev 	mutex_unlock(&isc->lock);
119991b4e487SEugen Hristev 
120091b4e487SEugen Hristev 	return ret;
120191b4e487SEugen Hristev }
120291b4e487SEugen Hristev 
120391b4e487SEugen Hristev static const struct v4l2_file_operations isc_fops = {
120491b4e487SEugen Hristev 	.owner		= THIS_MODULE,
120591b4e487SEugen Hristev 	.open		= isc_open,
120691b4e487SEugen Hristev 	.release	= isc_release,
120791b4e487SEugen Hristev 	.unlocked_ioctl	= video_ioctl2,
120891b4e487SEugen Hristev 	.read		= vb2_fop_read,
120991b4e487SEugen Hristev 	.mmap		= vb2_fop_mmap,
121091b4e487SEugen Hristev 	.poll		= vb2_fop_poll,
121191b4e487SEugen Hristev };
121291b4e487SEugen Hristev 
121391b4e487SEugen Hristev irqreturn_t microchip_isc_interrupt(int irq, void *dev_id)
121491b4e487SEugen Hristev {
121591b4e487SEugen Hristev 	struct isc_device *isc = (struct isc_device *)dev_id;
121691b4e487SEugen Hristev 	struct regmap *regmap = isc->regmap;
121791b4e487SEugen Hristev 	u32 isc_intsr, isc_intmask, pending;
121891b4e487SEugen Hristev 	irqreturn_t ret = IRQ_NONE;
121991b4e487SEugen Hristev 
122091b4e487SEugen Hristev 	regmap_read(regmap, ISC_INTSR, &isc_intsr);
122191b4e487SEugen Hristev 	regmap_read(regmap, ISC_INTMASK, &isc_intmask);
122291b4e487SEugen Hristev 
122391b4e487SEugen Hristev 	pending = isc_intsr & isc_intmask;
122491b4e487SEugen Hristev 
122591b4e487SEugen Hristev 	if (likely(pending & ISC_INT_DDONE)) {
122691b4e487SEugen Hristev 		spin_lock(&isc->dma_queue_lock);
122791b4e487SEugen Hristev 		if (isc->cur_frm) {
122891b4e487SEugen Hristev 			struct vb2_v4l2_buffer *vbuf = &isc->cur_frm->vb;
122991b4e487SEugen Hristev 			struct vb2_buffer *vb = &vbuf->vb2_buf;
123091b4e487SEugen Hristev 
123191b4e487SEugen Hristev 			vb->timestamp = ktime_get_ns();
123291b4e487SEugen Hristev 			vbuf->sequence = isc->sequence++;
123391b4e487SEugen Hristev 			vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
123491b4e487SEugen Hristev 			isc->cur_frm = NULL;
123591b4e487SEugen Hristev 		}
123691b4e487SEugen Hristev 
123791b4e487SEugen Hristev 		if (!list_empty(&isc->dma_queue) && !isc->stop) {
123891b4e487SEugen Hristev 			isc->cur_frm = list_first_entry(&isc->dma_queue,
123991b4e487SEugen Hristev 							struct isc_buffer, list);
124091b4e487SEugen Hristev 			list_del(&isc->cur_frm->list);
124191b4e487SEugen Hristev 
124291b4e487SEugen Hristev 			isc_start_dma(isc);
124391b4e487SEugen Hristev 		}
124491b4e487SEugen Hristev 
124591b4e487SEugen Hristev 		if (isc->stop)
124691b4e487SEugen Hristev 			complete(&isc->comp);
124791b4e487SEugen Hristev 
124891b4e487SEugen Hristev 		ret = IRQ_HANDLED;
124991b4e487SEugen Hristev 		spin_unlock(&isc->dma_queue_lock);
125091b4e487SEugen Hristev 	}
125191b4e487SEugen Hristev 
125291b4e487SEugen Hristev 	if (pending & ISC_INT_HISDONE) {
125391b4e487SEugen Hristev 		schedule_work(&isc->awb_work);
125491b4e487SEugen Hristev 		ret = IRQ_HANDLED;
125591b4e487SEugen Hristev 	}
125691b4e487SEugen Hristev 
125791b4e487SEugen Hristev 	return ret;
125891b4e487SEugen Hristev }
125991b4e487SEugen Hristev EXPORT_SYMBOL_GPL(microchip_isc_interrupt);
126091b4e487SEugen Hristev 
126191b4e487SEugen Hristev static void isc_hist_count(struct isc_device *isc, u32 *min, u32 *max)
126291b4e487SEugen Hristev {
126391b4e487SEugen Hristev 	struct regmap *regmap = isc->regmap;
126491b4e487SEugen Hristev 	struct isc_ctrls *ctrls = &isc->ctrls;
126591b4e487SEugen Hristev 	u32 *hist_count = &ctrls->hist_count[ctrls->hist_id];
126691b4e487SEugen Hristev 	u32 *hist_entry = &ctrls->hist_entry[0];
126791b4e487SEugen Hristev 	u32 i;
126891b4e487SEugen Hristev 
126991b4e487SEugen Hristev 	*min = 0;
127091b4e487SEugen Hristev 	*max = HIST_ENTRIES;
127191b4e487SEugen Hristev 
127291b4e487SEugen Hristev 	regmap_bulk_read(regmap, ISC_HIS_ENTRY + isc->offsets.his_entry,
127391b4e487SEugen Hristev 			 hist_entry, HIST_ENTRIES);
127491b4e487SEugen Hristev 
127591b4e487SEugen Hristev 	*hist_count = 0;
127691b4e487SEugen Hristev 	/*
127791b4e487SEugen Hristev 	 * we deliberately ignore the end of the histogram,
127891b4e487SEugen Hristev 	 * the most white pixels
127991b4e487SEugen Hristev 	 */
128091b4e487SEugen Hristev 	for (i = 1; i < HIST_ENTRIES; i++) {
128191b4e487SEugen Hristev 		if (*hist_entry && !*min)
128291b4e487SEugen Hristev 			*min = i;
128391b4e487SEugen Hristev 		if (*hist_entry)
128491b4e487SEugen Hristev 			*max = i;
128591b4e487SEugen Hristev 		*hist_count += i * (*hist_entry++);
128691b4e487SEugen Hristev 	}
128791b4e487SEugen Hristev 
128891b4e487SEugen Hristev 	if (!*min)
128991b4e487SEugen Hristev 		*min = 1;
129091b4e487SEugen Hristev 
1291*8d46c5cdSEugen Hristev 	dev_dbg(isc->dev, "isc wb: hist_id %u, hist_count %u",
129291b4e487SEugen Hristev 		ctrls->hist_id, *hist_count);
129391b4e487SEugen Hristev }
129491b4e487SEugen Hristev 
129591b4e487SEugen Hristev static void isc_wb_update(struct isc_ctrls *ctrls)
129691b4e487SEugen Hristev {
129791b4e487SEugen Hristev 	struct isc_device *isc = container_of(ctrls, struct isc_device, ctrls);
129891b4e487SEugen Hristev 	u32 *hist_count = &ctrls->hist_count[0];
129991b4e487SEugen Hristev 	u32 c, offset[4];
130091b4e487SEugen Hristev 	u64 avg = 0;
130191b4e487SEugen Hristev 	/* We compute two gains, stretch gain and grey world gain */
130291b4e487SEugen Hristev 	u32 s_gain[4], gw_gain[4];
130391b4e487SEugen Hristev 
130491b4e487SEugen Hristev 	/*
130591b4e487SEugen Hristev 	 * According to Grey World, we need to set gains for R/B to normalize
130691b4e487SEugen Hristev 	 * them towards the green channel.
130791b4e487SEugen Hristev 	 * Thus we want to keep Green as fixed and adjust only Red/Blue
130891b4e487SEugen Hristev 	 * Compute the average of the both green channels first
130991b4e487SEugen Hristev 	 */
131091b4e487SEugen Hristev 	avg = (u64)hist_count[ISC_HIS_CFG_MODE_GR] +
131191b4e487SEugen Hristev 		(u64)hist_count[ISC_HIS_CFG_MODE_GB];
131291b4e487SEugen Hristev 	avg >>= 1;
131391b4e487SEugen Hristev 
1314*8d46c5cdSEugen Hristev 	dev_dbg(isc->dev, "isc wb: green components average %llu\n", avg);
131591b4e487SEugen Hristev 
131691b4e487SEugen Hristev 	/* Green histogram is null, nothing to do */
131791b4e487SEugen Hristev 	if (!avg)
131891b4e487SEugen Hristev 		return;
131991b4e487SEugen Hristev 
132091b4e487SEugen Hristev 	for (c = ISC_HIS_CFG_MODE_GR; c <= ISC_HIS_CFG_MODE_B; c++) {
132191b4e487SEugen Hristev 		/*
132291b4e487SEugen Hristev 		 * the color offset is the minimum value of the histogram.
132391b4e487SEugen Hristev 		 * we stretch this color to the full range by substracting
132491b4e487SEugen Hristev 		 * this value from the color component.
132591b4e487SEugen Hristev 		 */
132691b4e487SEugen Hristev 		offset[c] = ctrls->hist_minmax[c][HIST_MIN_INDEX];
132791b4e487SEugen Hristev 		/*
132891b4e487SEugen Hristev 		 * The offset is always at least 1. If the offset is 1, we do
132991b4e487SEugen Hristev 		 * not need to adjust it, so our result must be zero.
133091b4e487SEugen Hristev 		 * the offset is computed in a histogram on 9 bits (0..512)
133191b4e487SEugen Hristev 		 * but the offset in register is based on
133291b4e487SEugen Hristev 		 * 12 bits pipeline (0..4096).
133391b4e487SEugen Hristev 		 * we need to shift with the 3 bits that the histogram is
133491b4e487SEugen Hristev 		 * ignoring
133591b4e487SEugen Hristev 		 */
133691b4e487SEugen Hristev 		ctrls->offset[c] = (offset[c] - 1) << 3;
133791b4e487SEugen Hristev 
133891b4e487SEugen Hristev 		/*
133991b4e487SEugen Hristev 		 * the offset is then taken and converted to 2's complements,
134091b4e487SEugen Hristev 		 * and must be negative, as we subtract this value from the
134191b4e487SEugen Hristev 		 * color components
134291b4e487SEugen Hristev 		 */
134391b4e487SEugen Hristev 		ctrls->offset[c] = -ctrls->offset[c];
134491b4e487SEugen Hristev 
134591b4e487SEugen Hristev 		/*
134691b4e487SEugen Hristev 		 * the stretch gain is the total number of histogram bins
134791b4e487SEugen Hristev 		 * divided by the actual range of color component (Max - Min)
134891b4e487SEugen Hristev 		 * If we compute gain like this, the actual color component
134991b4e487SEugen Hristev 		 * will be stretched to the full histogram.
135091b4e487SEugen Hristev 		 * We need to shift 9 bits for precision, we have 9 bits for
135191b4e487SEugen Hristev 		 * decimals
135291b4e487SEugen Hristev 		 */
135391b4e487SEugen Hristev 		s_gain[c] = (HIST_ENTRIES << 9) /
135491b4e487SEugen Hristev 			(ctrls->hist_minmax[c][HIST_MAX_INDEX] -
135591b4e487SEugen Hristev 			ctrls->hist_minmax[c][HIST_MIN_INDEX] + 1);
135691b4e487SEugen Hristev 
135791b4e487SEugen Hristev 		/*
135891b4e487SEugen Hristev 		 * Now we have to compute the gain w.r.t. the average.
135991b4e487SEugen Hristev 		 * Add/lose gain to the component towards the average.
136091b4e487SEugen Hristev 		 * If it happens that the component is zero, use the
136191b4e487SEugen Hristev 		 * fixed point value : 1.0 gain.
136291b4e487SEugen Hristev 		 */
136391b4e487SEugen Hristev 		if (hist_count[c])
136491b4e487SEugen Hristev 			gw_gain[c] = div_u64(avg << 9, hist_count[c]);
136591b4e487SEugen Hristev 		else
136691b4e487SEugen Hristev 			gw_gain[c] = 1 << 9;
136791b4e487SEugen Hristev 
1368*8d46c5cdSEugen Hristev 		dev_dbg(isc->dev,
136991b4e487SEugen Hristev 			"isc wb: component %d, s_gain %u, gw_gain %u\n",
137091b4e487SEugen Hristev 			c, s_gain[c], gw_gain[c]);
137191b4e487SEugen Hristev 		/* multiply both gains and adjust for decimals */
137291b4e487SEugen Hristev 		ctrls->gain[c] = s_gain[c] * gw_gain[c];
137391b4e487SEugen Hristev 		ctrls->gain[c] >>= 9;
137491b4e487SEugen Hristev 
137591b4e487SEugen Hristev 		/* make sure we are not out of range */
137691b4e487SEugen Hristev 		ctrls->gain[c] = clamp_val(ctrls->gain[c], 0, GENMASK(12, 0));
137791b4e487SEugen Hristev 
1378*8d46c5cdSEugen Hristev 		dev_dbg(isc->dev, "isc wb: component %d, final gain %u\n",
137991b4e487SEugen Hristev 			c, ctrls->gain[c]);
138091b4e487SEugen Hristev 	}
138191b4e487SEugen Hristev }
138291b4e487SEugen Hristev 
138391b4e487SEugen Hristev static void isc_awb_work(struct work_struct *w)
138491b4e487SEugen Hristev {
138591b4e487SEugen Hristev 	struct isc_device *isc =
138691b4e487SEugen Hristev 		container_of(w, struct isc_device, awb_work);
138791b4e487SEugen Hristev 	struct regmap *regmap = isc->regmap;
138891b4e487SEugen Hristev 	struct isc_ctrls *ctrls = &isc->ctrls;
138991b4e487SEugen Hristev 	u32 hist_id = ctrls->hist_id;
139091b4e487SEugen Hristev 	u32 baysel;
139191b4e487SEugen Hristev 	unsigned long flags;
139291b4e487SEugen Hristev 	u32 min, max;
139391b4e487SEugen Hristev 	int ret;
139491b4e487SEugen Hristev 
139591b4e487SEugen Hristev 	if (ctrls->hist_stat != HIST_ENABLED)
139691b4e487SEugen Hristev 		return;
139791b4e487SEugen Hristev 
139891b4e487SEugen Hristev 	isc_hist_count(isc, &min, &max);
139991b4e487SEugen Hristev 
1400*8d46c5cdSEugen Hristev 	dev_dbg(isc->dev,
140191b4e487SEugen Hristev 		"isc wb mode %d: hist min %u , max %u\n", hist_id, min, max);
140291b4e487SEugen Hristev 
140391b4e487SEugen Hristev 	ctrls->hist_minmax[hist_id][HIST_MIN_INDEX] = min;
140491b4e487SEugen Hristev 	ctrls->hist_minmax[hist_id][HIST_MAX_INDEX] = max;
140591b4e487SEugen Hristev 
140691b4e487SEugen Hristev 	if (hist_id != ISC_HIS_CFG_MODE_B) {
140791b4e487SEugen Hristev 		hist_id++;
140891b4e487SEugen Hristev 	} else {
140991b4e487SEugen Hristev 		isc_wb_update(ctrls);
141091b4e487SEugen Hristev 		hist_id = ISC_HIS_CFG_MODE_GR;
141191b4e487SEugen Hristev 	}
141291b4e487SEugen Hristev 
141391b4e487SEugen Hristev 	ctrls->hist_id = hist_id;
141491b4e487SEugen Hristev 	baysel = isc->config.sd_format->cfa_baycfg << ISC_HIS_CFG_BAYSEL_SHIFT;
141591b4e487SEugen Hristev 
141691b4e487SEugen Hristev 	ret = pm_runtime_resume_and_get(isc->dev);
141791b4e487SEugen Hristev 	if (ret < 0)
141891b4e487SEugen Hristev 		return;
141991b4e487SEugen Hristev 
142091b4e487SEugen Hristev 	/*
142191b4e487SEugen Hristev 	 * only update if we have all the required histograms and controls
142291b4e487SEugen Hristev 	 * if awb has been disabled, we need to reset registers as well.
142391b4e487SEugen Hristev 	 */
142491b4e487SEugen Hristev 	if (hist_id == ISC_HIS_CFG_MODE_GR || ctrls->awb == ISC_WB_NONE) {
142591b4e487SEugen Hristev 		/*
142691b4e487SEugen Hristev 		 * It may happen that DMA Done IRQ will trigger while we are
142791b4e487SEugen Hristev 		 * updating white balance registers here.
142891b4e487SEugen Hristev 		 * In that case, only parts of the controls have been updated.
142991b4e487SEugen Hristev 		 * We can avoid that by locking the section.
143091b4e487SEugen Hristev 		 */
143191b4e487SEugen Hristev 		spin_lock_irqsave(&isc->awb_lock, flags);
143291b4e487SEugen Hristev 		isc_update_awb_ctrls(isc);
143391b4e487SEugen Hristev 		spin_unlock_irqrestore(&isc->awb_lock, flags);
143491b4e487SEugen Hristev 
143591b4e487SEugen Hristev 		/*
143691b4e487SEugen Hristev 		 * if we are doing just the one time white balance adjustment,
143791b4e487SEugen Hristev 		 * we are basically done.
143891b4e487SEugen Hristev 		 */
143991b4e487SEugen Hristev 		if (ctrls->awb == ISC_WB_ONETIME) {
1440*8d46c5cdSEugen Hristev 			dev_info(isc->dev,
144191b4e487SEugen Hristev 				 "Completed one time white-balance adjustment.\n");
144291b4e487SEugen Hristev 			/* update the v4l2 controls values */
144391b4e487SEugen Hristev 			isc_update_v4l2_ctrls(isc);
144491b4e487SEugen Hristev 			ctrls->awb = ISC_WB_NONE;
144591b4e487SEugen Hristev 		}
144691b4e487SEugen Hristev 	}
144791b4e487SEugen Hristev 	regmap_write(regmap, ISC_HIS_CFG + isc->offsets.his,
144891b4e487SEugen Hristev 		     hist_id | baysel | ISC_HIS_CFG_RAR);
144991b4e487SEugen Hristev 
145091b4e487SEugen Hristev 	/*
145191b4e487SEugen Hristev 	 * We have to make sure the streaming has not stopped meanwhile.
145291b4e487SEugen Hristev 	 * ISC requires a frame to clock the internal profile update.
145391b4e487SEugen Hristev 	 * To avoid issues, lock the sequence with a mutex
145491b4e487SEugen Hristev 	 */
145591b4e487SEugen Hristev 	mutex_lock(&isc->awb_mutex);
145691b4e487SEugen Hristev 
145791b4e487SEugen Hristev 	/* streaming is not active anymore */
145891b4e487SEugen Hristev 	if (isc->stop) {
145991b4e487SEugen Hristev 		mutex_unlock(&isc->awb_mutex);
146091b4e487SEugen Hristev 		return;
146191b4e487SEugen Hristev 	}
146291b4e487SEugen Hristev 
146391b4e487SEugen Hristev 	isc_update_profile(isc);
146491b4e487SEugen Hristev 
146591b4e487SEugen Hristev 	mutex_unlock(&isc->awb_mutex);
146691b4e487SEugen Hristev 
146791b4e487SEugen Hristev 	/* if awb has been disabled, we don't need to start another histogram */
146891b4e487SEugen Hristev 	if (ctrls->awb)
146991b4e487SEugen Hristev 		regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ);
147091b4e487SEugen Hristev 
147191b4e487SEugen Hristev 	pm_runtime_put_sync(isc->dev);
147291b4e487SEugen Hristev }
147391b4e487SEugen Hristev 
147491b4e487SEugen Hristev static int isc_s_ctrl(struct v4l2_ctrl *ctrl)
147591b4e487SEugen Hristev {
147691b4e487SEugen Hristev 	struct isc_device *isc = container_of(ctrl->handler,
147791b4e487SEugen Hristev 					     struct isc_device, ctrls.handler);
147891b4e487SEugen Hristev 	struct isc_ctrls *ctrls = &isc->ctrls;
147991b4e487SEugen Hristev 
148091b4e487SEugen Hristev 	if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
148191b4e487SEugen Hristev 		return 0;
148291b4e487SEugen Hristev 
148391b4e487SEugen Hristev 	switch (ctrl->id) {
148491b4e487SEugen Hristev 	case V4L2_CID_BRIGHTNESS:
148591b4e487SEugen Hristev 		ctrls->brightness = ctrl->val & ISC_CBC_BRIGHT_MASK;
148691b4e487SEugen Hristev 		break;
148791b4e487SEugen Hristev 	case V4L2_CID_CONTRAST:
148891b4e487SEugen Hristev 		ctrls->contrast = ctrl->val & ISC_CBC_CONTRAST_MASK;
148991b4e487SEugen Hristev 		break;
149091b4e487SEugen Hristev 	case V4L2_CID_GAMMA:
149191b4e487SEugen Hristev 		ctrls->gamma_index = ctrl->val;
149291b4e487SEugen Hristev 		break;
149391b4e487SEugen Hristev 	default:
149491b4e487SEugen Hristev 		return -EINVAL;
149591b4e487SEugen Hristev 	}
149691b4e487SEugen Hristev 
149791b4e487SEugen Hristev 	return 0;
149891b4e487SEugen Hristev }
149991b4e487SEugen Hristev 
150091b4e487SEugen Hristev static const struct v4l2_ctrl_ops isc_ctrl_ops = {
150191b4e487SEugen Hristev 	.s_ctrl	= isc_s_ctrl,
150291b4e487SEugen Hristev };
150391b4e487SEugen Hristev 
150491b4e487SEugen Hristev static int isc_s_awb_ctrl(struct v4l2_ctrl *ctrl)
150591b4e487SEugen Hristev {
150691b4e487SEugen Hristev 	struct isc_device *isc = container_of(ctrl->handler,
150791b4e487SEugen Hristev 					     struct isc_device, ctrls.handler);
150891b4e487SEugen Hristev 	struct isc_ctrls *ctrls = &isc->ctrls;
150991b4e487SEugen Hristev 
151091b4e487SEugen Hristev 	if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
151191b4e487SEugen Hristev 		return 0;
151291b4e487SEugen Hristev 
151391b4e487SEugen Hristev 	switch (ctrl->id) {
151491b4e487SEugen Hristev 	case V4L2_CID_AUTO_WHITE_BALANCE:
151591b4e487SEugen Hristev 		if (ctrl->val == 1)
151691b4e487SEugen Hristev 			ctrls->awb = ISC_WB_AUTO;
151791b4e487SEugen Hristev 		else
151891b4e487SEugen Hristev 			ctrls->awb = ISC_WB_NONE;
151991b4e487SEugen Hristev 
152091b4e487SEugen Hristev 		/* configure the controls with new values from v4l2 */
152191b4e487SEugen Hristev 		if (ctrl->cluster[ISC_CTRL_R_GAIN]->is_new)
152291b4e487SEugen Hristev 			ctrls->gain[ISC_HIS_CFG_MODE_R] = isc->r_gain_ctrl->val;
152391b4e487SEugen Hristev 		if (ctrl->cluster[ISC_CTRL_B_GAIN]->is_new)
152491b4e487SEugen Hristev 			ctrls->gain[ISC_HIS_CFG_MODE_B] = isc->b_gain_ctrl->val;
152591b4e487SEugen Hristev 		if (ctrl->cluster[ISC_CTRL_GR_GAIN]->is_new)
152691b4e487SEugen Hristev 			ctrls->gain[ISC_HIS_CFG_MODE_GR] = isc->gr_gain_ctrl->val;
152791b4e487SEugen Hristev 		if (ctrl->cluster[ISC_CTRL_GB_GAIN]->is_new)
152891b4e487SEugen Hristev 			ctrls->gain[ISC_HIS_CFG_MODE_GB] = isc->gb_gain_ctrl->val;
152991b4e487SEugen Hristev 
153091b4e487SEugen Hristev 		if (ctrl->cluster[ISC_CTRL_R_OFF]->is_new)
153191b4e487SEugen Hristev 			ctrls->offset[ISC_HIS_CFG_MODE_R] = isc->r_off_ctrl->val;
153291b4e487SEugen Hristev 		if (ctrl->cluster[ISC_CTRL_B_OFF]->is_new)
153391b4e487SEugen Hristev 			ctrls->offset[ISC_HIS_CFG_MODE_B] = isc->b_off_ctrl->val;
153491b4e487SEugen Hristev 		if (ctrl->cluster[ISC_CTRL_GR_OFF]->is_new)
153591b4e487SEugen Hristev 			ctrls->offset[ISC_HIS_CFG_MODE_GR] = isc->gr_off_ctrl->val;
153691b4e487SEugen Hristev 		if (ctrl->cluster[ISC_CTRL_GB_OFF]->is_new)
153791b4e487SEugen Hristev 			ctrls->offset[ISC_HIS_CFG_MODE_GB] = isc->gb_off_ctrl->val;
153891b4e487SEugen Hristev 
153991b4e487SEugen Hristev 		isc_update_awb_ctrls(isc);
154091b4e487SEugen Hristev 
154191b4e487SEugen Hristev 		mutex_lock(&isc->awb_mutex);
154291b4e487SEugen Hristev 		if (vb2_is_streaming(&isc->vb2_vidq)) {
154391b4e487SEugen Hristev 			/*
154491b4e487SEugen Hristev 			 * If we are streaming, we can update profile to
154591b4e487SEugen Hristev 			 * have the new settings in place.
154691b4e487SEugen Hristev 			 */
154791b4e487SEugen Hristev 			isc_update_profile(isc);
154891b4e487SEugen Hristev 		} else {
154991b4e487SEugen Hristev 			/*
155091b4e487SEugen Hristev 			 * The auto cluster will activate automatically this
155191b4e487SEugen Hristev 			 * control. This has to be deactivated when not
155291b4e487SEugen Hristev 			 * streaming.
155391b4e487SEugen Hristev 			 */
155491b4e487SEugen Hristev 			v4l2_ctrl_activate(isc->do_wb_ctrl, false);
155591b4e487SEugen Hristev 		}
155691b4e487SEugen Hristev 		mutex_unlock(&isc->awb_mutex);
155791b4e487SEugen Hristev 
155891b4e487SEugen Hristev 		/* if we have autowhitebalance on, start histogram procedure */
155991b4e487SEugen Hristev 		if (ctrls->awb == ISC_WB_AUTO &&
156091b4e487SEugen Hristev 		    vb2_is_streaming(&isc->vb2_vidq) &&
156191b4e487SEugen Hristev 		    ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code))
156291b4e487SEugen Hristev 			isc_set_histogram(isc, true);
156391b4e487SEugen Hristev 
156491b4e487SEugen Hristev 		/*
156591b4e487SEugen Hristev 		 * for one time whitebalance adjustment, check the button,
156691b4e487SEugen Hristev 		 * if it's pressed, perform the one time operation.
156791b4e487SEugen Hristev 		 */
156891b4e487SEugen Hristev 		if (ctrls->awb == ISC_WB_NONE &&
156991b4e487SEugen Hristev 		    ctrl->cluster[ISC_CTRL_DO_WB]->is_new &&
157091b4e487SEugen Hristev 		    !(ctrl->cluster[ISC_CTRL_DO_WB]->flags &
157191b4e487SEugen Hristev 		    V4L2_CTRL_FLAG_INACTIVE)) {
157291b4e487SEugen Hristev 			ctrls->awb = ISC_WB_ONETIME;
157391b4e487SEugen Hristev 			isc_set_histogram(isc, true);
1574*8d46c5cdSEugen Hristev 			dev_dbg(isc->dev, "One time white-balance started.\n");
157591b4e487SEugen Hristev 		}
157691b4e487SEugen Hristev 		return 0;
157791b4e487SEugen Hristev 	}
157891b4e487SEugen Hristev 	return 0;
157991b4e487SEugen Hristev }
158091b4e487SEugen Hristev 
158191b4e487SEugen Hristev static int isc_g_volatile_awb_ctrl(struct v4l2_ctrl *ctrl)
158291b4e487SEugen Hristev {
158391b4e487SEugen Hristev 	struct isc_device *isc = container_of(ctrl->handler,
158491b4e487SEugen Hristev 					     struct isc_device, ctrls.handler);
158591b4e487SEugen Hristev 	struct isc_ctrls *ctrls = &isc->ctrls;
158691b4e487SEugen Hristev 
158791b4e487SEugen Hristev 	switch (ctrl->id) {
158891b4e487SEugen Hristev 	/* being a cluster, this id will be called for every control */
158991b4e487SEugen Hristev 	case V4L2_CID_AUTO_WHITE_BALANCE:
159091b4e487SEugen Hristev 		ctrl->cluster[ISC_CTRL_R_GAIN]->val =
159191b4e487SEugen Hristev 					ctrls->gain[ISC_HIS_CFG_MODE_R];
159291b4e487SEugen Hristev 		ctrl->cluster[ISC_CTRL_B_GAIN]->val =
159391b4e487SEugen Hristev 					ctrls->gain[ISC_HIS_CFG_MODE_B];
159491b4e487SEugen Hristev 		ctrl->cluster[ISC_CTRL_GR_GAIN]->val =
159591b4e487SEugen Hristev 					ctrls->gain[ISC_HIS_CFG_MODE_GR];
159691b4e487SEugen Hristev 		ctrl->cluster[ISC_CTRL_GB_GAIN]->val =
159791b4e487SEugen Hristev 					ctrls->gain[ISC_HIS_CFG_MODE_GB];
159891b4e487SEugen Hristev 
159991b4e487SEugen Hristev 		ctrl->cluster[ISC_CTRL_R_OFF]->val =
160091b4e487SEugen Hristev 			ctrls->offset[ISC_HIS_CFG_MODE_R];
160191b4e487SEugen Hristev 		ctrl->cluster[ISC_CTRL_B_OFF]->val =
160291b4e487SEugen Hristev 			ctrls->offset[ISC_HIS_CFG_MODE_B];
160391b4e487SEugen Hristev 		ctrl->cluster[ISC_CTRL_GR_OFF]->val =
160491b4e487SEugen Hristev 			ctrls->offset[ISC_HIS_CFG_MODE_GR];
160591b4e487SEugen Hristev 		ctrl->cluster[ISC_CTRL_GB_OFF]->val =
160691b4e487SEugen Hristev 			ctrls->offset[ISC_HIS_CFG_MODE_GB];
160791b4e487SEugen Hristev 		break;
160891b4e487SEugen Hristev 	}
160991b4e487SEugen Hristev 	return 0;
161091b4e487SEugen Hristev }
161191b4e487SEugen Hristev 
161291b4e487SEugen Hristev static const struct v4l2_ctrl_ops isc_awb_ops = {
161391b4e487SEugen Hristev 	.s_ctrl = isc_s_awb_ctrl,
161491b4e487SEugen Hristev 	.g_volatile_ctrl = isc_g_volatile_awb_ctrl,
161591b4e487SEugen Hristev };
161691b4e487SEugen Hristev 
161791b4e487SEugen Hristev #define ISC_CTRL_OFF(_name, _id, _name_str) \
161891b4e487SEugen Hristev 	static const struct v4l2_ctrl_config _name = { \
161991b4e487SEugen Hristev 		.ops = &isc_awb_ops, \
162091b4e487SEugen Hristev 		.id = _id, \
162191b4e487SEugen Hristev 		.name = _name_str, \
162291b4e487SEugen Hristev 		.type = V4L2_CTRL_TYPE_INTEGER, \
162391b4e487SEugen Hristev 		.flags = V4L2_CTRL_FLAG_SLIDER, \
162491b4e487SEugen Hristev 		.min = -4095, \
162591b4e487SEugen Hristev 		.max = 4095, \
162691b4e487SEugen Hristev 		.step = 1, \
162791b4e487SEugen Hristev 		.def = 0, \
162891b4e487SEugen Hristev 	}
162991b4e487SEugen Hristev 
163091b4e487SEugen Hristev ISC_CTRL_OFF(isc_r_off_ctrl, ISC_CID_R_OFFSET, "Red Component Offset");
163191b4e487SEugen Hristev ISC_CTRL_OFF(isc_b_off_ctrl, ISC_CID_B_OFFSET, "Blue Component Offset");
163291b4e487SEugen Hristev ISC_CTRL_OFF(isc_gr_off_ctrl, ISC_CID_GR_OFFSET, "Green Red Component Offset");
163391b4e487SEugen Hristev ISC_CTRL_OFF(isc_gb_off_ctrl, ISC_CID_GB_OFFSET, "Green Blue Component Offset");
163491b4e487SEugen Hristev 
163591b4e487SEugen Hristev #define ISC_CTRL_GAIN(_name, _id, _name_str) \
163691b4e487SEugen Hristev 	static const struct v4l2_ctrl_config _name = { \
163791b4e487SEugen Hristev 		.ops = &isc_awb_ops, \
163891b4e487SEugen Hristev 		.id = _id, \
163991b4e487SEugen Hristev 		.name = _name_str, \
164091b4e487SEugen Hristev 		.type = V4L2_CTRL_TYPE_INTEGER, \
164191b4e487SEugen Hristev 		.flags = V4L2_CTRL_FLAG_SLIDER, \
164291b4e487SEugen Hristev 		.min = 0, \
164391b4e487SEugen Hristev 		.max = 8191, \
164491b4e487SEugen Hristev 		.step = 1, \
164591b4e487SEugen Hristev 		.def = 512, \
164691b4e487SEugen Hristev 	}
164791b4e487SEugen Hristev 
164891b4e487SEugen Hristev ISC_CTRL_GAIN(isc_r_gain_ctrl, ISC_CID_R_GAIN, "Red Component Gain");
164991b4e487SEugen Hristev ISC_CTRL_GAIN(isc_b_gain_ctrl, ISC_CID_B_GAIN, "Blue Component Gain");
165091b4e487SEugen Hristev ISC_CTRL_GAIN(isc_gr_gain_ctrl, ISC_CID_GR_GAIN, "Green Red Component Gain");
165191b4e487SEugen Hristev ISC_CTRL_GAIN(isc_gb_gain_ctrl, ISC_CID_GB_GAIN, "Green Blue Component Gain");
165291b4e487SEugen Hristev 
165391b4e487SEugen Hristev static int isc_ctrl_init(struct isc_device *isc)
165491b4e487SEugen Hristev {
165591b4e487SEugen Hristev 	const struct v4l2_ctrl_ops *ops = &isc_ctrl_ops;
165691b4e487SEugen Hristev 	struct isc_ctrls *ctrls = &isc->ctrls;
165791b4e487SEugen Hristev 	struct v4l2_ctrl_handler *hdl = &ctrls->handler;
165891b4e487SEugen Hristev 	int ret;
165991b4e487SEugen Hristev 
166091b4e487SEugen Hristev 	ctrls->hist_stat = HIST_INIT;
166191b4e487SEugen Hristev 	isc_reset_awb_ctrls(isc);
166291b4e487SEugen Hristev 
166391b4e487SEugen Hristev 	ret = v4l2_ctrl_handler_init(hdl, 13);
166491b4e487SEugen Hristev 	if (ret < 0)
166591b4e487SEugen Hristev 		return ret;
166691b4e487SEugen Hristev 
166791b4e487SEugen Hristev 	/* Initialize product specific controls. For example, contrast */
166891b4e487SEugen Hristev 	isc->config_ctrls(isc, ops);
166991b4e487SEugen Hristev 
167091b4e487SEugen Hristev 	ctrls->brightness = 0;
167191b4e487SEugen Hristev 
167291b4e487SEugen Hristev 	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -1024, 1023, 1, 0);
167391b4e487SEugen Hristev 	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAMMA, 0, isc->gamma_max, 1,
167491b4e487SEugen Hristev 			  isc->gamma_max);
167591b4e487SEugen Hristev 	isc->awb_ctrl = v4l2_ctrl_new_std(hdl, &isc_awb_ops,
167691b4e487SEugen Hristev 					  V4L2_CID_AUTO_WHITE_BALANCE,
167791b4e487SEugen Hristev 					  0, 1, 1, 1);
167891b4e487SEugen Hristev 
167991b4e487SEugen Hristev 	/* do_white_balance is a button, so min,max,step,default are ignored */
168091b4e487SEugen Hristev 	isc->do_wb_ctrl = v4l2_ctrl_new_std(hdl, &isc_awb_ops,
168191b4e487SEugen Hristev 					    V4L2_CID_DO_WHITE_BALANCE,
168291b4e487SEugen Hristev 					    0, 0, 0, 0);
168391b4e487SEugen Hristev 
168491b4e487SEugen Hristev 	if (!isc->do_wb_ctrl) {
168591b4e487SEugen Hristev 		ret = hdl->error;
168691b4e487SEugen Hristev 		v4l2_ctrl_handler_free(hdl);
168791b4e487SEugen Hristev 		return ret;
168891b4e487SEugen Hristev 	}
168991b4e487SEugen Hristev 
169091b4e487SEugen Hristev 	v4l2_ctrl_activate(isc->do_wb_ctrl, false);
169191b4e487SEugen Hristev 
169291b4e487SEugen Hristev 	isc->r_gain_ctrl = v4l2_ctrl_new_custom(hdl, &isc_r_gain_ctrl, NULL);
169391b4e487SEugen Hristev 	isc->b_gain_ctrl = v4l2_ctrl_new_custom(hdl, &isc_b_gain_ctrl, NULL);
169491b4e487SEugen Hristev 	isc->gr_gain_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gr_gain_ctrl, NULL);
169591b4e487SEugen Hristev 	isc->gb_gain_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gb_gain_ctrl, NULL);
169691b4e487SEugen Hristev 	isc->r_off_ctrl = v4l2_ctrl_new_custom(hdl, &isc_r_off_ctrl, NULL);
169791b4e487SEugen Hristev 	isc->b_off_ctrl = v4l2_ctrl_new_custom(hdl, &isc_b_off_ctrl, NULL);
169891b4e487SEugen Hristev 	isc->gr_off_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gr_off_ctrl, NULL);
169991b4e487SEugen Hristev 	isc->gb_off_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gb_off_ctrl, NULL);
170091b4e487SEugen Hristev 
170191b4e487SEugen Hristev 	/*
170291b4e487SEugen Hristev 	 * The cluster is in auto mode with autowhitebalance enabled
170391b4e487SEugen Hristev 	 * and manual mode otherwise.
170491b4e487SEugen Hristev 	 */
170591b4e487SEugen Hristev 	v4l2_ctrl_auto_cluster(10, &isc->awb_ctrl, 0, true);
170691b4e487SEugen Hristev 
170791b4e487SEugen Hristev 	v4l2_ctrl_handler_setup(hdl);
170891b4e487SEugen Hristev 
170991b4e487SEugen Hristev 	return 0;
171091b4e487SEugen Hristev }
171191b4e487SEugen Hristev 
171291b4e487SEugen Hristev static int isc_async_bound(struct v4l2_async_notifier *notifier,
171391b4e487SEugen Hristev 			   struct v4l2_subdev *subdev,
171491b4e487SEugen Hristev 			   struct v4l2_async_subdev *asd)
171591b4e487SEugen Hristev {
171691b4e487SEugen Hristev 	struct isc_device *isc = container_of(notifier->v4l2_dev,
171791b4e487SEugen Hristev 					      struct isc_device, v4l2_dev);
171891b4e487SEugen Hristev 	struct isc_subdev_entity *subdev_entity =
171991b4e487SEugen Hristev 		container_of(notifier, struct isc_subdev_entity, notifier);
1720920b2665SEugen Hristev 	int pad;
172191b4e487SEugen Hristev 
172291b4e487SEugen Hristev 	if (video_is_registered(&isc->video_dev)) {
1723*8d46c5cdSEugen Hristev 		dev_err(isc->dev, "only supports one sub-device.\n");
172491b4e487SEugen Hristev 		return -EBUSY;
172591b4e487SEugen Hristev 	}
172691b4e487SEugen Hristev 
172791b4e487SEugen Hristev 	subdev_entity->sd = subdev;
172891b4e487SEugen Hristev 
1729920b2665SEugen Hristev 	pad = media_entity_get_fwnode_pad(&subdev->entity, asd->match.fwnode,
1730920b2665SEugen Hristev 					  MEDIA_PAD_FL_SOURCE);
1731920b2665SEugen Hristev 	if (pad < 0) {
1732*8d46c5cdSEugen Hristev 		dev_err(isc->dev, "failed to find pad for %s\n", subdev->name);
1733920b2665SEugen Hristev 		return pad;
1734920b2665SEugen Hristev 	}
1735920b2665SEugen Hristev 
1736920b2665SEugen Hristev 	isc->remote_pad = pad;
1737920b2665SEugen Hristev 
173891b4e487SEugen Hristev 	return 0;
173991b4e487SEugen Hristev }
174091b4e487SEugen Hristev 
174191b4e487SEugen Hristev static void isc_async_unbind(struct v4l2_async_notifier *notifier,
174291b4e487SEugen Hristev 			     struct v4l2_subdev *subdev,
174391b4e487SEugen Hristev 			     struct v4l2_async_subdev *asd)
174491b4e487SEugen Hristev {
174591b4e487SEugen Hristev 	struct isc_device *isc = container_of(notifier->v4l2_dev,
174691b4e487SEugen Hristev 					      struct isc_device, v4l2_dev);
174791b4e487SEugen Hristev 	mutex_destroy(&isc->awb_mutex);
174891b4e487SEugen Hristev 	cancel_work_sync(&isc->awb_work);
174991b4e487SEugen Hristev 	video_unregister_device(&isc->video_dev);
175091b4e487SEugen Hristev 	v4l2_ctrl_handler_free(&isc->ctrls.handler);
175191b4e487SEugen Hristev }
175291b4e487SEugen Hristev 
1753920b2665SEugen Hristev struct isc_format *isc_find_format_by_code(struct isc_device *isc,
175491b4e487SEugen Hristev 					   unsigned int code, int *index)
175591b4e487SEugen Hristev {
175691b4e487SEugen Hristev 	struct isc_format *fmt = &isc->formats_list[0];
175791b4e487SEugen Hristev 	unsigned int i;
175891b4e487SEugen Hristev 
175991b4e487SEugen Hristev 	for (i = 0; i < isc->formats_list_size; i++) {
176091b4e487SEugen Hristev 		if (fmt->mbus_code == code) {
176191b4e487SEugen Hristev 			*index = i;
176291b4e487SEugen Hristev 			return fmt;
176391b4e487SEugen Hristev 		}
176491b4e487SEugen Hristev 
176591b4e487SEugen Hristev 		fmt++;
176691b4e487SEugen Hristev 	}
176791b4e487SEugen Hristev 
176891b4e487SEugen Hristev 	return NULL;
176991b4e487SEugen Hristev }
1770920b2665SEugen Hristev EXPORT_SYMBOL_GPL(isc_find_format_by_code);
177191b4e487SEugen Hristev 
177291b4e487SEugen Hristev static int isc_set_default_fmt(struct isc_device *isc)
177391b4e487SEugen Hristev {
177491b4e487SEugen Hristev 	struct v4l2_format f = {
177591b4e487SEugen Hristev 		.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
177691b4e487SEugen Hristev 		.fmt.pix = {
177791b4e487SEugen Hristev 			.width		= VGA_WIDTH,
177891b4e487SEugen Hristev 			.height		= VGA_HEIGHT,
177991b4e487SEugen Hristev 			.field		= V4L2_FIELD_NONE,
178078ba0d79SEugen Hristev 			.pixelformat	= isc->controller_formats[0].fourcc,
178191b4e487SEugen Hristev 		},
178291b4e487SEugen Hristev 	};
178391b4e487SEugen Hristev 	int ret;
178491b4e487SEugen Hristev 
178578ba0d79SEugen Hristev 	ret = isc_try_fmt(isc, &f);
178691b4e487SEugen Hristev 	if (ret)
178791b4e487SEugen Hristev 		return ret;
178891b4e487SEugen Hristev 
178991b4e487SEugen Hristev 	isc->fmt = f;
179091b4e487SEugen Hristev 	return 0;
179191b4e487SEugen Hristev }
179291b4e487SEugen Hristev 
179391b4e487SEugen Hristev static int isc_async_complete(struct v4l2_async_notifier *notifier)
179491b4e487SEugen Hristev {
179591b4e487SEugen Hristev 	struct isc_device *isc = container_of(notifier->v4l2_dev,
179691b4e487SEugen Hristev 					      struct isc_device, v4l2_dev);
179791b4e487SEugen Hristev 	struct video_device *vdev = &isc->video_dev;
179891b4e487SEugen Hristev 	struct vb2_queue *q = &isc->vb2_vidq;
179991b4e487SEugen Hristev 	int ret = 0;
180091b4e487SEugen Hristev 
180191b4e487SEugen Hristev 	INIT_WORK(&isc->awb_work, isc_awb_work);
180291b4e487SEugen Hristev 
180391b4e487SEugen Hristev 	ret = v4l2_device_register_subdev_nodes(&isc->v4l2_dev);
180491b4e487SEugen Hristev 	if (ret < 0) {
1805*8d46c5cdSEugen Hristev 		dev_err(isc->dev, "Failed to register subdev nodes\n");
180691b4e487SEugen Hristev 		return ret;
180791b4e487SEugen Hristev 	}
180891b4e487SEugen Hristev 
180991b4e487SEugen Hristev 	isc->current_subdev = container_of(notifier,
181091b4e487SEugen Hristev 					   struct isc_subdev_entity, notifier);
181191b4e487SEugen Hristev 	mutex_init(&isc->lock);
181291b4e487SEugen Hristev 	mutex_init(&isc->awb_mutex);
181391b4e487SEugen Hristev 
181491b4e487SEugen Hristev 	init_completion(&isc->comp);
181591b4e487SEugen Hristev 
181691b4e487SEugen Hristev 	/* Initialize videobuf2 queue */
181791b4e487SEugen Hristev 	q->type			= V4L2_BUF_TYPE_VIDEO_CAPTURE;
181891b4e487SEugen Hristev 	q->io_modes		= VB2_MMAP | VB2_DMABUF | VB2_READ;
181991b4e487SEugen Hristev 	q->drv_priv		= isc;
182091b4e487SEugen Hristev 	q->buf_struct_size	= sizeof(struct isc_buffer);
182191b4e487SEugen Hristev 	q->ops			= &isc_vb2_ops;
182291b4e487SEugen Hristev 	q->mem_ops		= &vb2_dma_contig_memops;
182391b4e487SEugen Hristev 	q->timestamp_flags	= V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
182491b4e487SEugen Hristev 	q->lock			= &isc->lock;
182591b4e487SEugen Hristev 	q->min_buffers_needed	= 1;
182691b4e487SEugen Hristev 	q->dev			= isc->dev;
182791b4e487SEugen Hristev 
182891b4e487SEugen Hristev 	ret = vb2_queue_init(q);
182991b4e487SEugen Hristev 	if (ret < 0) {
1830*8d46c5cdSEugen Hristev 		dev_err(isc->dev, "vb2_queue_init() failed: %d\n", ret);
183191b4e487SEugen Hristev 		goto isc_async_complete_err;
183291b4e487SEugen Hristev 	}
183391b4e487SEugen Hristev 
183491b4e487SEugen Hristev 	/* Init video dma queues */
183591b4e487SEugen Hristev 	INIT_LIST_HEAD(&isc->dma_queue);
183691b4e487SEugen Hristev 	spin_lock_init(&isc->dma_queue_lock);
183791b4e487SEugen Hristev 	spin_lock_init(&isc->awb_lock);
183891b4e487SEugen Hristev 
183991b4e487SEugen Hristev 	ret = isc_set_default_fmt(isc);
184091b4e487SEugen Hristev 	if (ret) {
1841*8d46c5cdSEugen Hristev 		dev_err(isc->dev, "Could not set default format\n");
184291b4e487SEugen Hristev 		goto isc_async_complete_err;
184391b4e487SEugen Hristev 	}
184491b4e487SEugen Hristev 
184591b4e487SEugen Hristev 	ret = isc_ctrl_init(isc);
184691b4e487SEugen Hristev 	if (ret) {
1847*8d46c5cdSEugen Hristev 		dev_err(isc->dev, "Init isc ctrols failed: %d\n", ret);
184891b4e487SEugen Hristev 		goto isc_async_complete_err;
184991b4e487SEugen Hristev 	}
185091b4e487SEugen Hristev 
185191b4e487SEugen Hristev 	/* Register video device */
185291b4e487SEugen Hristev 	strscpy(vdev->name, KBUILD_MODNAME, sizeof(vdev->name));
185391b4e487SEugen Hristev 	vdev->release		= video_device_release_empty;
185491b4e487SEugen Hristev 	vdev->fops		= &isc_fops;
185591b4e487SEugen Hristev 	vdev->ioctl_ops		= &isc_ioctl_ops;
185691b4e487SEugen Hristev 	vdev->v4l2_dev		= &isc->v4l2_dev;
185791b4e487SEugen Hristev 	vdev->vfl_dir		= VFL_DIR_RX;
185891b4e487SEugen Hristev 	vdev->queue		= q;
185991b4e487SEugen Hristev 	vdev->lock		= &isc->lock;
186091b4e487SEugen Hristev 	vdev->ctrl_handler	= &isc->ctrls.handler;
186178ba0d79SEugen Hristev 	vdev->device_caps	= V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE |
186278ba0d79SEugen Hristev 				  V4L2_CAP_IO_MC;
186391b4e487SEugen Hristev 	video_set_drvdata(vdev, isc);
186491b4e487SEugen Hristev 
186591b4e487SEugen Hristev 	ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
186691b4e487SEugen Hristev 	if (ret < 0) {
1867*8d46c5cdSEugen Hristev 		dev_err(isc->dev, "video_register_device failed: %d\n", ret);
186891b4e487SEugen Hristev 		goto isc_async_complete_err;
186991b4e487SEugen Hristev 	}
187091b4e487SEugen Hristev 
1871920b2665SEugen Hristev 	ret = isc_scaler_link(isc);
1872920b2665SEugen Hristev 	if (ret < 0)
1873920b2665SEugen Hristev 		goto isc_async_complete_unregister_device;
1874920b2665SEugen Hristev 
1875920b2665SEugen Hristev 	ret = media_device_register(&isc->mdev);
1876920b2665SEugen Hristev 	if (ret < 0)
1877920b2665SEugen Hristev 		goto isc_async_complete_unregister_device;
1878920b2665SEugen Hristev 
187991b4e487SEugen Hristev 	return 0;
188091b4e487SEugen Hristev 
1881920b2665SEugen Hristev isc_async_complete_unregister_device:
1882920b2665SEugen Hristev 	video_unregister_device(vdev);
1883920b2665SEugen Hristev 
188491b4e487SEugen Hristev isc_async_complete_err:
188591b4e487SEugen Hristev 	mutex_destroy(&isc->awb_mutex);
188691b4e487SEugen Hristev 	mutex_destroy(&isc->lock);
188791b4e487SEugen Hristev 	return ret;
188891b4e487SEugen Hristev }
188991b4e487SEugen Hristev 
189091b4e487SEugen Hristev const struct v4l2_async_notifier_operations microchip_isc_async_ops = {
189191b4e487SEugen Hristev 	.bound = isc_async_bound,
189291b4e487SEugen Hristev 	.unbind = isc_async_unbind,
189391b4e487SEugen Hristev 	.complete = isc_async_complete,
189491b4e487SEugen Hristev };
189591b4e487SEugen Hristev EXPORT_SYMBOL_GPL(microchip_isc_async_ops);
189691b4e487SEugen Hristev 
189791b4e487SEugen Hristev void microchip_isc_subdev_cleanup(struct isc_device *isc)
189891b4e487SEugen Hristev {
189991b4e487SEugen Hristev 	struct isc_subdev_entity *subdev_entity;
190091b4e487SEugen Hristev 
190191b4e487SEugen Hristev 	list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
190291b4e487SEugen Hristev 		v4l2_async_nf_unregister(&subdev_entity->notifier);
190391b4e487SEugen Hristev 		v4l2_async_nf_cleanup(&subdev_entity->notifier);
190491b4e487SEugen Hristev 	}
190591b4e487SEugen Hristev 
190691b4e487SEugen Hristev 	INIT_LIST_HEAD(&isc->subdev_entities);
190791b4e487SEugen Hristev }
190891b4e487SEugen Hristev EXPORT_SYMBOL_GPL(microchip_isc_subdev_cleanup);
190991b4e487SEugen Hristev 
191091b4e487SEugen Hristev int microchip_isc_pipeline_init(struct isc_device *isc)
191191b4e487SEugen Hristev {
191291b4e487SEugen Hristev 	struct device *dev = isc->dev;
191391b4e487SEugen Hristev 	struct regmap *regmap = isc->regmap;
191491b4e487SEugen Hristev 	struct regmap_field *regs;
191591b4e487SEugen Hristev 	unsigned int i;
191691b4e487SEugen Hristev 
191791b4e487SEugen Hristev 	/*
191891b4e487SEugen Hristev 	 * DPCEN-->GDCEN-->BLCEN-->WB-->CFA-->CC-->
191991b4e487SEugen Hristev 	 * GAM-->VHXS-->CSC-->CBC-->SUB422-->SUB420
192091b4e487SEugen Hristev 	 */
192191b4e487SEugen Hristev 	const struct reg_field regfields[ISC_PIPE_LINE_NODE_NUM] = {
192291b4e487SEugen Hristev 		REG_FIELD(ISC_DPC_CTRL, 0, 0),
192391b4e487SEugen Hristev 		REG_FIELD(ISC_DPC_CTRL, 1, 1),
192491b4e487SEugen Hristev 		REG_FIELD(ISC_DPC_CTRL, 2, 2),
192591b4e487SEugen Hristev 		REG_FIELD(ISC_WB_CTRL, 0, 0),
192691b4e487SEugen Hristev 		REG_FIELD(ISC_CFA_CTRL, 0, 0),
192791b4e487SEugen Hristev 		REG_FIELD(ISC_CC_CTRL, 0, 0),
192891b4e487SEugen Hristev 		REG_FIELD(ISC_GAM_CTRL, 0, 0),
192991b4e487SEugen Hristev 		REG_FIELD(ISC_GAM_CTRL, 1, 1),
193091b4e487SEugen Hristev 		REG_FIELD(ISC_GAM_CTRL, 2, 2),
193191b4e487SEugen Hristev 		REG_FIELD(ISC_GAM_CTRL, 3, 3),
193291b4e487SEugen Hristev 		REG_FIELD(ISC_VHXS_CTRL, 0, 0),
193391b4e487SEugen Hristev 		REG_FIELD(ISC_CSC_CTRL + isc->offsets.csc, 0, 0),
193491b4e487SEugen Hristev 		REG_FIELD(ISC_CBC_CTRL + isc->offsets.cbc, 0, 0),
193591b4e487SEugen Hristev 		REG_FIELD(ISC_SUB422_CTRL + isc->offsets.sub422, 0, 0),
193691b4e487SEugen Hristev 		REG_FIELD(ISC_SUB420_CTRL + isc->offsets.sub420, 0, 0),
193791b4e487SEugen Hristev 	};
193891b4e487SEugen Hristev 
193991b4e487SEugen Hristev 	for (i = 0; i < ISC_PIPE_LINE_NODE_NUM; i++) {
194091b4e487SEugen Hristev 		regs = devm_regmap_field_alloc(dev, regmap, regfields[i]);
194191b4e487SEugen Hristev 		if (IS_ERR(regs))
194291b4e487SEugen Hristev 			return PTR_ERR(regs);
194391b4e487SEugen Hristev 
194491b4e487SEugen Hristev 		isc->pipeline[i] =  regs;
194591b4e487SEugen Hristev 	}
194691b4e487SEugen Hristev 
194791b4e487SEugen Hristev 	return 0;
194891b4e487SEugen Hristev }
194991b4e487SEugen Hristev EXPORT_SYMBOL_GPL(microchip_isc_pipeline_init);
195091b4e487SEugen Hristev 
195178ba0d79SEugen Hristev static int isc_link_validate(struct media_link *link)
195278ba0d79SEugen Hristev {
195378ba0d79SEugen Hristev 	struct video_device *vdev =
195478ba0d79SEugen Hristev 		media_entity_to_video_device(link->sink->entity);
195578ba0d79SEugen Hristev 	struct isc_device *isc = video_get_drvdata(vdev);
195678ba0d79SEugen Hristev 	int ret;
195778ba0d79SEugen Hristev 
195878ba0d79SEugen Hristev 	ret = v4l2_subdev_link_validate(link);
195978ba0d79SEugen Hristev 	if (ret)
196078ba0d79SEugen Hristev 		return ret;
196178ba0d79SEugen Hristev 
196278ba0d79SEugen Hristev 	return isc_validate(isc);
196378ba0d79SEugen Hristev }
196478ba0d79SEugen Hristev 
196578ba0d79SEugen Hristev static const struct media_entity_operations isc_entity_operations = {
196678ba0d79SEugen Hristev 	.link_validate = isc_link_validate,
196778ba0d79SEugen Hristev };
196878ba0d79SEugen Hristev 
1969920b2665SEugen Hristev int isc_mc_init(struct isc_device *isc, u32 ver)
1970920b2665SEugen Hristev {
1971920b2665SEugen Hristev 	const struct of_device_id *match;
1972920b2665SEugen Hristev 	int ret;
1973920b2665SEugen Hristev 
1974920b2665SEugen Hristev 	isc->video_dev.entity.function = MEDIA_ENT_F_IO_V4L;
1975920b2665SEugen Hristev 	isc->video_dev.entity.flags = MEDIA_ENT_FL_DEFAULT;
197678ba0d79SEugen Hristev 	isc->video_dev.entity.ops = &isc_entity_operations;
197778ba0d79SEugen Hristev 
1978920b2665SEugen Hristev 	isc->pads[ISC_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
1979920b2665SEugen Hristev 
1980920b2665SEugen Hristev 	ret = media_entity_pads_init(&isc->video_dev.entity, ISC_PADS_NUM,
1981920b2665SEugen Hristev 				     isc->pads);
1982920b2665SEugen Hristev 	if (ret < 0) {
1983920b2665SEugen Hristev 		dev_err(isc->dev, "media entity init failed\n");
1984920b2665SEugen Hristev 		return ret;
1985920b2665SEugen Hristev 	}
1986920b2665SEugen Hristev 
1987920b2665SEugen Hristev 	isc->mdev.dev = isc->dev;
1988920b2665SEugen Hristev 
1989920b2665SEugen Hristev 	match = of_match_node(isc->dev->driver->of_match_table,
1990920b2665SEugen Hristev 			      isc->dev->of_node);
1991920b2665SEugen Hristev 
1992920b2665SEugen Hristev 	strscpy(isc->mdev.driver_name, KBUILD_MODNAME,
1993920b2665SEugen Hristev 		sizeof(isc->mdev.driver_name));
1994920b2665SEugen Hristev 	strscpy(isc->mdev.model, match->compatible, sizeof(isc->mdev.model));
1995920b2665SEugen Hristev 	snprintf(isc->mdev.bus_info, sizeof(isc->mdev.bus_info), "platform:%s",
1996920b2665SEugen Hristev 		 isc->v4l2_dev.name);
1997920b2665SEugen Hristev 	isc->mdev.hw_revision = ver;
1998920b2665SEugen Hristev 
1999920b2665SEugen Hristev 	media_device_init(&isc->mdev);
2000920b2665SEugen Hristev 
2001920b2665SEugen Hristev 	isc->v4l2_dev.mdev = &isc->mdev;
2002920b2665SEugen Hristev 
2003920b2665SEugen Hristev 	return isc_scaler_init(isc);
2004920b2665SEugen Hristev }
2005920b2665SEugen Hristev EXPORT_SYMBOL_GPL(isc_mc_init);
2006920b2665SEugen Hristev 
2007920b2665SEugen Hristev void isc_mc_cleanup(struct isc_device *isc)
2008920b2665SEugen Hristev {
2009920b2665SEugen Hristev 	media_entity_cleanup(&isc->video_dev.entity);
2010920b2665SEugen Hristev 	media_device_cleanup(&isc->mdev);
2011920b2665SEugen Hristev }
2012920b2665SEugen Hristev EXPORT_SYMBOL_GPL(isc_mc_cleanup);
2013920b2665SEugen Hristev 
201491b4e487SEugen Hristev /* regmap configuration */
201591b4e487SEugen Hristev #define MICROCHIP_ISC_REG_MAX    0xd5c
201691b4e487SEugen Hristev const struct regmap_config microchip_isc_regmap_config = {
201791b4e487SEugen Hristev 	.reg_bits       = 32,
201891b4e487SEugen Hristev 	.reg_stride     = 4,
201991b4e487SEugen Hristev 	.val_bits       = 32,
202091b4e487SEugen Hristev 	.max_register	= MICROCHIP_ISC_REG_MAX,
202191b4e487SEugen Hristev };
202291b4e487SEugen Hristev EXPORT_SYMBOL_GPL(microchip_isc_regmap_config);
202391b4e487SEugen Hristev 
202491b4e487SEugen Hristev MODULE_AUTHOR("Songjun Wu");
202591b4e487SEugen Hristev MODULE_AUTHOR("Eugen Hristev");
202691b4e487SEugen Hristev MODULE_DESCRIPTION("Microchip ISC common code base");
202791b4e487SEugen Hristev MODULE_LICENSE("GPL v2");
2028