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 
isc_update_v4l2_ctrls(struct isc_device * isc)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 
isc_update_awb_ctrls(struct isc_device * isc)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 
isc_reset_awb_ctrls(struct isc_device * isc)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 
isc_queue_setup(struct vb2_queue * vq,unsigned int * nbuffers,unsigned int * nplanes,unsigned int sizes[],struct device * alloc_devs[])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 
isc_buffer_prepare(struct vb2_buffer * vb)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) {
1138d46c5cdSEugen 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 
isc_crop_pfe(struct isc_device * isc)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 
isc_start_dma(struct isc_device * isc)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 
isc_set_pipeline(struct isc_device * isc,u32 pipeline)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 
isc_update_profile(struct isc_device * isc)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 
isc_set_histogram(struct isc_device * isc,bool enable)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 
isc_configure(struct isc_device * isc)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 
isc_prepare_streaming(struct vb2_queue * vq)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 
isc_start_streaming(struct vb2_queue * vq,unsigned int count)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) {
3458d46c5cdSEugen 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) {
3518d46c5cdSEugen 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 
isc_unprepare_streaming(struct vb2_queue * vq)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 
isc_stop_streaming(struct vb2_queue * vq)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))
4218d46c5cdSEugen 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)
4338d46c5cdSEugen 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 
isc_buffer_queue(struct vb2_buffer * vb)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 
isc_querycap(struct file * file,void * priv,struct v4l2_capability * cap)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 
isc_enum_fmt_vid_cap(struct file * file,void * priv,struct v4l2_fmtdesc * f)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 
isc_g_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * fmt)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  */
isc_try_validate_formats(struct isc_device * isc)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 */
6178d46c5cdSEugen Hristev 		dev_err(isc->dev, "Requested unsupported format.\n");
61891b4e487SEugen Hristev 		ret = -EINVAL;
61991b4e487SEugen Hristev 	}
6208d46c5cdSEugen 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)) {
6268d46c5cdSEugen 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)) {
6328d46c5cdSEugen 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)) {
6388d46c5cdSEugen 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  */
isc_try_configure_rlp_dma(struct isc_device * isc,bool direct_dump)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  */
isc_try_configure_pipeline(struct isc_device * isc)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 
isc_try_fse(struct isc_device * isc,struct v4l2_subdev_state * sd_state)85891b4e487SEugen Hristev static void isc_try_fse(struct isc_device *isc,
85991b4e487SEugen Hristev 			struct v4l2_subdev_state *sd_state)
86091b4e487SEugen Hristev {
861e18a7e9aSLaurent Pinchart 	struct v4l2_subdev_frame_size_enum fse = {
862e18a7e9aSLaurent Pinchart 		.which = V4L2_SUBDEV_FORMAT_TRY,
863e18a7e9aSLaurent Pinchart 	};
86491b4e487SEugen Hristev 	int ret;
86591b4e487SEugen Hristev 
86691b4e487SEugen Hristev 	/*
86791b4e487SEugen Hristev 	 * If we do not know yet which format the subdev is using, we cannot
86891b4e487SEugen Hristev 	 * do anything.
86991b4e487SEugen Hristev 	 */
87078ba0d79SEugen Hristev 	if (!isc->config.sd_format)
87191b4e487SEugen Hristev 		return;
87291b4e487SEugen Hristev 
87391b4e487SEugen Hristev 	fse.code = isc->try_config.sd_format->mbus_code;
87491b4e487SEugen Hristev 
87591b4e487SEugen Hristev 	ret = v4l2_subdev_call(isc->current_subdev->sd, pad, enum_frame_size,
87691b4e487SEugen Hristev 			       sd_state, &fse);
87791b4e487SEugen Hristev 	/*
87891b4e487SEugen Hristev 	 * Attempt to obtain format size from subdev. If not available,
87991b4e487SEugen Hristev 	 * just use the maximum ISC can receive.
88091b4e487SEugen Hristev 	 */
88191b4e487SEugen Hristev 	if (ret) {
88291b4e487SEugen Hristev 		sd_state->pads->try_crop.width = isc->max_width;
88391b4e487SEugen Hristev 		sd_state->pads->try_crop.height = isc->max_height;
88491b4e487SEugen Hristev 	} else {
88591b4e487SEugen Hristev 		sd_state->pads->try_crop.width = fse.max_width;
88691b4e487SEugen Hristev 		sd_state->pads->try_crop.height = fse.max_height;
88791b4e487SEugen Hristev 	}
88891b4e487SEugen Hristev }
88991b4e487SEugen Hristev 
isc_try_fmt(struct isc_device * isc,struct v4l2_format * f)89078ba0d79SEugen Hristev static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f)
89191b4e487SEugen Hristev {
89291b4e487SEugen Hristev 	struct v4l2_pix_format *pixfmt = &f->fmt.pix;
89378ba0d79SEugen Hristev 	unsigned int i;
89491b4e487SEugen Hristev 
89591b4e487SEugen Hristev 	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
89691b4e487SEugen Hristev 		return -EINVAL;
89791b4e487SEugen Hristev 
89878ba0d79SEugen Hristev 	isc->try_config.fourcc = isc->controller_formats[0].fourcc;
89978ba0d79SEugen Hristev 
90078ba0d79SEugen Hristev 	/* find if the format requested is supported */
90178ba0d79SEugen Hristev 	for (i = 0; i < isc->controller_formats_size; i++)
90278ba0d79SEugen Hristev 		if (isc->controller_formats[i].fourcc == pixfmt->pixelformat) {
90378ba0d79SEugen Hristev 			isc->try_config.fourcc = pixfmt->pixelformat;
90491b4e487SEugen Hristev 			break;
90591b4e487SEugen Hristev 		}
90691b4e487SEugen Hristev 
90778ba0d79SEugen Hristev 	isc_try_configure_rlp_dma(isc, false);
90891b4e487SEugen Hristev 
90991b4e487SEugen Hristev 	/* Limit to Microchip ISC hardware capabilities */
91078ba0d79SEugen Hristev 	v4l_bound_align_image(&pixfmt->width, 16, isc->max_width, 0,
91178ba0d79SEugen Hristev 			      &pixfmt->height, 16, isc->max_height, 0, 0);
91278ba0d79SEugen Hristev 	/* If we did not find the requested format, we will fallback here */
91378ba0d79SEugen Hristev 	pixfmt->pixelformat = isc->try_config.fourcc;
91478ba0d79SEugen Hristev 	pixfmt->colorspace = V4L2_COLORSPACE_SRGB;
91591b4e487SEugen Hristev 	pixfmt->field = V4L2_FIELD_NONE;
91678ba0d79SEugen Hristev 
91791b4e487SEugen Hristev 	pixfmt->bytesperline = (pixfmt->width * isc->try_config.bpp_v4l2) >> 3;
91891b4e487SEugen Hristev 	pixfmt->sizeimage = ((pixfmt->width * isc->try_config.bpp) >> 3) *
91991b4e487SEugen Hristev 			     pixfmt->height;
92091b4e487SEugen Hristev 
92178ba0d79SEugen Hristev 	isc->try_fmt = *f;
92291b4e487SEugen Hristev 
92391b4e487SEugen Hristev 	return 0;
92491b4e487SEugen Hristev }
92591b4e487SEugen Hristev 
isc_set_fmt(struct isc_device * isc,struct v4l2_format * f)92691b4e487SEugen Hristev static int isc_set_fmt(struct isc_device *isc, struct v4l2_format *f)
92791b4e487SEugen Hristev {
92878ba0d79SEugen Hristev 	isc_try_fmt(isc, f);
92978ba0d79SEugen Hristev 
93078ba0d79SEugen Hristev 	/* make the try configuration active */
93178ba0d79SEugen Hristev 	isc->config = isc->try_config;
93278ba0d79SEugen Hristev 	isc->fmt = isc->try_fmt;
93378ba0d79SEugen Hristev 
9348d46c5cdSEugen Hristev 	dev_dbg(isc->dev, "ISC set_fmt to %.4s @%dx%d\n",
93578ba0d79SEugen Hristev 		(char *)&f->fmt.pix.pixelformat,
93678ba0d79SEugen Hristev 		f->fmt.pix.width, f->fmt.pix.height);
93778ba0d79SEugen Hristev 
93878ba0d79SEugen Hristev 	return 0;
93978ba0d79SEugen Hristev }
94078ba0d79SEugen Hristev 
isc_validate(struct isc_device * isc)94178ba0d79SEugen Hristev static int isc_validate(struct isc_device *isc)
94278ba0d79SEugen Hristev {
94378ba0d79SEugen Hristev 	int ret;
94478ba0d79SEugen Hristev 	int i;
94578ba0d79SEugen Hristev 	struct isc_format *sd_fmt = NULL;
94678ba0d79SEugen Hristev 	struct v4l2_pix_format *pixfmt = &isc->fmt.fmt.pix;
94791b4e487SEugen Hristev 	struct v4l2_subdev_format format = {
94891b4e487SEugen Hristev 		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
94978ba0d79SEugen Hristev 		.pad = isc->remote_pad,
95091b4e487SEugen Hristev 	};
95178ba0d79SEugen Hristev 	struct v4l2_subdev_pad_config pad_cfg = {};
95278ba0d79SEugen Hristev 	struct v4l2_subdev_state pad_state = {
95378ba0d79SEugen Hristev 		.pads = &pad_cfg,
95478ba0d79SEugen Hristev 	};
95591b4e487SEugen Hristev 
95678ba0d79SEugen Hristev 	/* Get current format from subdev */
95778ba0d79SEugen Hristev 	ret = v4l2_subdev_call(isc->current_subdev->sd, pad, get_fmt, NULL,
95878ba0d79SEugen Hristev 			       &format);
95991b4e487SEugen Hristev 	if (ret)
96091b4e487SEugen Hristev 		return ret;
96191b4e487SEugen Hristev 
96278ba0d79SEugen Hristev 	/* Identify the subdev's format configuration */
96378ba0d79SEugen Hristev 	for (i = 0; i < isc->formats_list_size; i++)
96478ba0d79SEugen Hristev 		if (isc->formats_list[i].mbus_code == format.format.code) {
96578ba0d79SEugen Hristev 			sd_fmt = &isc->formats_list[i];
96678ba0d79SEugen Hristev 			break;
96778ba0d79SEugen Hristev 		}
96878ba0d79SEugen Hristev 
96978ba0d79SEugen Hristev 	/* Check if the format is not supported */
97078ba0d79SEugen Hristev 	if (!sd_fmt) {
9718d46c5cdSEugen Hristev 		dev_err(isc->dev,
97278ba0d79SEugen Hristev 			"Current subdevice is streaming a media bus code that is not supported 0x%x\n",
97378ba0d79SEugen Hristev 			format.format.code);
97478ba0d79SEugen Hristev 		return -EPIPE;
97578ba0d79SEugen Hristev 	}
97678ba0d79SEugen Hristev 
97778ba0d79SEugen Hristev 	/* At this moment we know which format the subdev will use */
97878ba0d79SEugen Hristev 	isc->try_config.sd_format = sd_fmt;
97978ba0d79SEugen Hristev 
98078ba0d79SEugen Hristev 	/* If the sensor is not RAW, we can only do a direct dump */
98178ba0d79SEugen Hristev 	if (!ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code))
98278ba0d79SEugen Hristev 		isc_try_configure_rlp_dma(isc, true);
98391b4e487SEugen Hristev 
98491b4e487SEugen Hristev 	/* Limit to Microchip ISC hardware capabilities */
98578ba0d79SEugen Hristev 	v4l_bound_align_image(&format.format.width, 16, isc->max_width, 0,
98678ba0d79SEugen Hristev 			      &format.format.height, 16, isc->max_height, 0, 0);
98791b4e487SEugen Hristev 
98878ba0d79SEugen Hristev 	/* Check if the frame size is the same. Otherwise we may overflow */
98978ba0d79SEugen Hristev 	if (pixfmt->height != format.format.height ||
99078ba0d79SEugen Hristev 	    pixfmt->width != format.format.width) {
9918d46c5cdSEugen Hristev 		dev_err(isc->dev,
99278ba0d79SEugen Hristev 			"ISC not configured with the proper frame size: %dx%d\n",
99378ba0d79SEugen Hristev 			format.format.width, format.format.height);
99478ba0d79SEugen Hristev 		return -EPIPE;
99578ba0d79SEugen Hristev 	}
99691b4e487SEugen Hristev 
9978d46c5cdSEugen Hristev 	dev_dbg(isc->dev,
99878ba0d79SEugen Hristev 		"Identified subdev using format %.4s with %dx%d %d bpp\n",
99978ba0d79SEugen Hristev 		(char *)&sd_fmt->fourcc, pixfmt->width, pixfmt->height,
100078ba0d79SEugen Hristev 		isc->try_config.bpp);
100178ba0d79SEugen Hristev 
100278ba0d79SEugen Hristev 	/* Reset and restart AWB if the subdevice changed the format */
100391b4e487SEugen Hristev 	if (isc->try_config.sd_format && isc->config.sd_format &&
100491b4e487SEugen Hristev 	    isc->try_config.sd_format != isc->config.sd_format) {
100591b4e487SEugen Hristev 		isc->ctrls.hist_stat = HIST_INIT;
100691b4e487SEugen Hristev 		isc_reset_awb_ctrls(isc);
100791b4e487SEugen Hristev 		isc_update_v4l2_ctrls(isc);
100891b4e487SEugen Hristev 	}
100978ba0d79SEugen Hristev 
101078ba0d79SEugen Hristev 	/* Validate formats */
101178ba0d79SEugen Hristev 	ret = isc_try_validate_formats(isc);
101278ba0d79SEugen Hristev 	if (ret)
101378ba0d79SEugen Hristev 		return ret;
101478ba0d79SEugen Hristev 
101578ba0d79SEugen Hristev 	/* Obtain frame sizes if possible to have crop requirements ready */
101678ba0d79SEugen Hristev 	isc_try_fse(isc, &pad_state);
101778ba0d79SEugen Hristev 
101878ba0d79SEugen Hristev 	/* Configure ISC pipeline for the config */
101978ba0d79SEugen Hristev 	ret = isc_try_configure_pipeline(isc);
102078ba0d79SEugen Hristev 	if (ret)
102178ba0d79SEugen Hristev 		return ret;
102278ba0d79SEugen Hristev 
102391b4e487SEugen Hristev 	isc->config = isc->try_config;
102491b4e487SEugen Hristev 
10258d46c5cdSEugen Hristev 	dev_dbg(isc->dev, "New ISC configuration in place\n");
102691b4e487SEugen Hristev 
102791b4e487SEugen Hristev 	return 0;
102891b4e487SEugen Hristev }
102991b4e487SEugen Hristev 
isc_s_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)103091b4e487SEugen Hristev static int isc_s_fmt_vid_cap(struct file *file, void *priv,
103191b4e487SEugen Hristev 			     struct v4l2_format *f)
103291b4e487SEugen Hristev {
103391b4e487SEugen Hristev 	struct isc_device *isc = video_drvdata(file);
103491b4e487SEugen Hristev 
103591b4e487SEugen Hristev 	if (vb2_is_busy(&isc->vb2_vidq))
103691b4e487SEugen Hristev 		return -EBUSY;
103791b4e487SEugen Hristev 
103891b4e487SEugen Hristev 	return isc_set_fmt(isc, f);
103991b4e487SEugen Hristev }
104091b4e487SEugen Hristev 
isc_try_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)104191b4e487SEugen Hristev static int isc_try_fmt_vid_cap(struct file *file, void *priv,
104291b4e487SEugen Hristev 			       struct v4l2_format *f)
104391b4e487SEugen Hristev {
104491b4e487SEugen Hristev 	struct isc_device *isc = video_drvdata(file);
104591b4e487SEugen Hristev 
104678ba0d79SEugen Hristev 	return isc_try_fmt(isc, f);
104791b4e487SEugen Hristev }
104891b4e487SEugen Hristev 
isc_enum_input(struct file * file,void * priv,struct v4l2_input * inp)104991b4e487SEugen Hristev static int isc_enum_input(struct file *file, void *priv,
105091b4e487SEugen Hristev 			  struct v4l2_input *inp)
105191b4e487SEugen Hristev {
105291b4e487SEugen Hristev 	if (inp->index != 0)
105391b4e487SEugen Hristev 		return -EINVAL;
105491b4e487SEugen Hristev 
105591b4e487SEugen Hristev 	inp->type = V4L2_INPUT_TYPE_CAMERA;
105691b4e487SEugen Hristev 	inp->std = 0;
105791b4e487SEugen Hristev 	strscpy(inp->name, "Camera", sizeof(inp->name));
105891b4e487SEugen Hristev 
105991b4e487SEugen Hristev 	return 0;
106091b4e487SEugen Hristev }
106191b4e487SEugen Hristev 
isc_g_input(struct file * file,void * priv,unsigned int * i)106291b4e487SEugen Hristev static int isc_g_input(struct file *file, void *priv, unsigned int *i)
106391b4e487SEugen Hristev {
106491b4e487SEugen Hristev 	*i = 0;
106591b4e487SEugen Hristev 
106691b4e487SEugen Hristev 	return 0;
106791b4e487SEugen Hristev }
106891b4e487SEugen Hristev 
isc_s_input(struct file * file,void * priv,unsigned int i)106991b4e487SEugen Hristev static int isc_s_input(struct file *file, void *priv, unsigned int i)
107091b4e487SEugen Hristev {
107191b4e487SEugen Hristev 	if (i > 0)
107291b4e487SEugen Hristev 		return -EINVAL;
107391b4e487SEugen Hristev 
107491b4e487SEugen Hristev 	return 0;
107591b4e487SEugen Hristev }
107691b4e487SEugen Hristev 
isc_g_parm(struct file * file,void * fh,struct v4l2_streamparm * a)107791b4e487SEugen Hristev static int isc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
107891b4e487SEugen Hristev {
107991b4e487SEugen Hristev 	struct isc_device *isc = video_drvdata(file);
108091b4e487SEugen Hristev 
108191b4e487SEugen Hristev 	return v4l2_g_parm_cap(video_devdata(file), isc->current_subdev->sd, a);
108291b4e487SEugen Hristev }
108391b4e487SEugen Hristev 
isc_s_parm(struct file * file,void * fh,struct v4l2_streamparm * a)108491b4e487SEugen Hristev static int isc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
108591b4e487SEugen Hristev {
108691b4e487SEugen Hristev 	struct isc_device *isc = video_drvdata(file);
108791b4e487SEugen Hristev 
108891b4e487SEugen Hristev 	return v4l2_s_parm_cap(video_devdata(file), isc->current_subdev->sd, a);
108991b4e487SEugen Hristev }
109091b4e487SEugen Hristev 
isc_enum_framesizes(struct file * file,void * fh,struct v4l2_frmsizeenum * fsize)109191b4e487SEugen Hristev static int isc_enum_framesizes(struct file *file, void *fh,
109291b4e487SEugen Hristev 			       struct v4l2_frmsizeenum *fsize)
109391b4e487SEugen Hristev {
109491b4e487SEugen Hristev 	struct isc_device *isc = video_drvdata(file);
109591b4e487SEugen Hristev 	int ret = -EINVAL;
109691b4e487SEugen Hristev 	int i;
109791b4e487SEugen Hristev 
109891b4e487SEugen Hristev 	if (fsize->index)
109991b4e487SEugen Hristev 		return -EINVAL;
110091b4e487SEugen Hristev 
110191b4e487SEugen Hristev 	for (i = 0; i < isc->controller_formats_size; i++)
110291b4e487SEugen Hristev 		if (isc->controller_formats[i].fourcc == fsize->pixel_format)
110391b4e487SEugen Hristev 			ret = 0;
110491b4e487SEugen Hristev 
110591b4e487SEugen Hristev 	if (ret)
110691b4e487SEugen Hristev 		return ret;
110791b4e487SEugen Hristev 
110891b4e487SEugen Hristev 	fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
110991b4e487SEugen Hristev 
111091b4e487SEugen Hristev 	fsize->stepwise.min_width = 16;
111191b4e487SEugen Hristev 	fsize->stepwise.max_width = isc->max_width;
111291b4e487SEugen Hristev 	fsize->stepwise.min_height = 16;
111391b4e487SEugen Hristev 	fsize->stepwise.max_height = isc->max_height;
111491b4e487SEugen Hristev 	fsize->stepwise.step_width = 1;
111591b4e487SEugen Hristev 	fsize->stepwise.step_height = 1;
111691b4e487SEugen Hristev 
111791b4e487SEugen Hristev 	return 0;
111891b4e487SEugen Hristev }
111991b4e487SEugen Hristev 
112091b4e487SEugen Hristev static const struct v4l2_ioctl_ops isc_ioctl_ops = {
112191b4e487SEugen Hristev 	.vidioc_querycap		= isc_querycap,
112291b4e487SEugen Hristev 	.vidioc_enum_fmt_vid_cap	= isc_enum_fmt_vid_cap,
112391b4e487SEugen Hristev 	.vidioc_g_fmt_vid_cap		= isc_g_fmt_vid_cap,
112491b4e487SEugen Hristev 	.vidioc_s_fmt_vid_cap		= isc_s_fmt_vid_cap,
112591b4e487SEugen Hristev 	.vidioc_try_fmt_vid_cap		= isc_try_fmt_vid_cap,
112691b4e487SEugen Hristev 
112791b4e487SEugen Hristev 	.vidioc_enum_input		= isc_enum_input,
112891b4e487SEugen Hristev 	.vidioc_g_input			= isc_g_input,
112991b4e487SEugen Hristev 	.vidioc_s_input			= isc_s_input,
113091b4e487SEugen Hristev 
113191b4e487SEugen Hristev 	.vidioc_reqbufs			= vb2_ioctl_reqbufs,
113291b4e487SEugen Hristev 	.vidioc_querybuf		= vb2_ioctl_querybuf,
113391b4e487SEugen Hristev 	.vidioc_qbuf			= vb2_ioctl_qbuf,
113491b4e487SEugen Hristev 	.vidioc_expbuf			= vb2_ioctl_expbuf,
113591b4e487SEugen Hristev 	.vidioc_dqbuf			= vb2_ioctl_dqbuf,
113691b4e487SEugen Hristev 	.vidioc_create_bufs		= vb2_ioctl_create_bufs,
113791b4e487SEugen Hristev 	.vidioc_prepare_buf		= vb2_ioctl_prepare_buf,
113891b4e487SEugen Hristev 	.vidioc_streamon		= vb2_ioctl_streamon,
113991b4e487SEugen Hristev 	.vidioc_streamoff		= vb2_ioctl_streamoff,
114091b4e487SEugen Hristev 
114191b4e487SEugen Hristev 	.vidioc_g_parm			= isc_g_parm,
114291b4e487SEugen Hristev 	.vidioc_s_parm			= isc_s_parm,
114391b4e487SEugen Hristev 	.vidioc_enum_framesizes		= isc_enum_framesizes,
114491b4e487SEugen Hristev 
114591b4e487SEugen Hristev 	.vidioc_log_status		= v4l2_ctrl_log_status,
114691b4e487SEugen Hristev 	.vidioc_subscribe_event		= v4l2_ctrl_subscribe_event,
114791b4e487SEugen Hristev 	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
114891b4e487SEugen Hristev };
114991b4e487SEugen Hristev 
isc_open(struct file * file)115091b4e487SEugen Hristev static int isc_open(struct file *file)
115191b4e487SEugen Hristev {
115291b4e487SEugen Hristev 	struct isc_device *isc = video_drvdata(file);
115391b4e487SEugen Hristev 	struct v4l2_subdev *sd = isc->current_subdev->sd;
115491b4e487SEugen Hristev 	int ret;
115591b4e487SEugen Hristev 
115691b4e487SEugen Hristev 	if (mutex_lock_interruptible(&isc->lock))
115791b4e487SEugen Hristev 		return -ERESTARTSYS;
115891b4e487SEugen Hristev 
115991b4e487SEugen Hristev 	ret = v4l2_fh_open(file);
116091b4e487SEugen Hristev 	if (ret < 0)
116191b4e487SEugen Hristev 		goto unlock;
116291b4e487SEugen Hristev 
116391b4e487SEugen Hristev 	if (!v4l2_fh_is_singular_file(file))
116491b4e487SEugen Hristev 		goto unlock;
116591b4e487SEugen Hristev 
116691b4e487SEugen Hristev 	ret = v4l2_subdev_call(sd, core, s_power, 1);
116791b4e487SEugen Hristev 	if (ret < 0 && ret != -ENOIOCTLCMD) {
116891b4e487SEugen Hristev 		v4l2_fh_release(file);
116991b4e487SEugen Hristev 		goto unlock;
117091b4e487SEugen Hristev 	}
117191b4e487SEugen Hristev 
117291b4e487SEugen Hristev 	ret = isc_set_fmt(isc, &isc->fmt);
117391b4e487SEugen Hristev 	if (ret) {
117491b4e487SEugen Hristev 		v4l2_subdev_call(sd, core, s_power, 0);
117591b4e487SEugen Hristev 		v4l2_fh_release(file);
117691b4e487SEugen Hristev 	}
117791b4e487SEugen Hristev 
117891b4e487SEugen Hristev unlock:
117991b4e487SEugen Hristev 	mutex_unlock(&isc->lock);
118091b4e487SEugen Hristev 	return ret;
118191b4e487SEugen Hristev }
118291b4e487SEugen Hristev 
isc_release(struct file * file)118391b4e487SEugen Hristev static int isc_release(struct file *file)
118491b4e487SEugen Hristev {
118591b4e487SEugen Hristev 	struct isc_device *isc = video_drvdata(file);
118691b4e487SEugen Hristev 	struct v4l2_subdev *sd = isc->current_subdev->sd;
118791b4e487SEugen Hristev 	bool fh_singular;
118891b4e487SEugen Hristev 	int ret;
118991b4e487SEugen Hristev 
119091b4e487SEugen Hristev 	mutex_lock(&isc->lock);
119191b4e487SEugen Hristev 
119291b4e487SEugen Hristev 	fh_singular = v4l2_fh_is_singular_file(file);
119391b4e487SEugen Hristev 
119491b4e487SEugen Hristev 	ret = _vb2_fop_release(file, NULL);
119591b4e487SEugen Hristev 
119691b4e487SEugen Hristev 	if (fh_singular)
119791b4e487SEugen Hristev 		v4l2_subdev_call(sd, core, s_power, 0);
119891b4e487SEugen Hristev 
119991b4e487SEugen Hristev 	mutex_unlock(&isc->lock);
120091b4e487SEugen Hristev 
120191b4e487SEugen Hristev 	return ret;
120291b4e487SEugen Hristev }
120391b4e487SEugen Hristev 
120491b4e487SEugen Hristev static const struct v4l2_file_operations isc_fops = {
120591b4e487SEugen Hristev 	.owner		= THIS_MODULE,
120691b4e487SEugen Hristev 	.open		= isc_open,
120791b4e487SEugen Hristev 	.release	= isc_release,
120891b4e487SEugen Hristev 	.unlocked_ioctl	= video_ioctl2,
120991b4e487SEugen Hristev 	.read		= vb2_fop_read,
121091b4e487SEugen Hristev 	.mmap		= vb2_fop_mmap,
121191b4e487SEugen Hristev 	.poll		= vb2_fop_poll,
121291b4e487SEugen Hristev };
121391b4e487SEugen Hristev 
microchip_isc_interrupt(int irq,void * dev_id)121491b4e487SEugen Hristev irqreturn_t microchip_isc_interrupt(int irq, void *dev_id)
121591b4e487SEugen Hristev {
121691b4e487SEugen Hristev 	struct isc_device *isc = (struct isc_device *)dev_id;
121791b4e487SEugen Hristev 	struct regmap *regmap = isc->regmap;
121891b4e487SEugen Hristev 	u32 isc_intsr, isc_intmask, pending;
121991b4e487SEugen Hristev 	irqreturn_t ret = IRQ_NONE;
122091b4e487SEugen Hristev 
122191b4e487SEugen Hristev 	regmap_read(regmap, ISC_INTSR, &isc_intsr);
122291b4e487SEugen Hristev 	regmap_read(regmap, ISC_INTMASK, &isc_intmask);
122391b4e487SEugen Hristev 
122491b4e487SEugen Hristev 	pending = isc_intsr & isc_intmask;
122591b4e487SEugen Hristev 
122691b4e487SEugen Hristev 	if (likely(pending & ISC_INT_DDONE)) {
122791b4e487SEugen Hristev 		spin_lock(&isc->dma_queue_lock);
122891b4e487SEugen Hristev 		if (isc->cur_frm) {
122991b4e487SEugen Hristev 			struct vb2_v4l2_buffer *vbuf = &isc->cur_frm->vb;
123091b4e487SEugen Hristev 			struct vb2_buffer *vb = &vbuf->vb2_buf;
123191b4e487SEugen Hristev 
123291b4e487SEugen Hristev 			vb->timestamp = ktime_get_ns();
123391b4e487SEugen Hristev 			vbuf->sequence = isc->sequence++;
123491b4e487SEugen Hristev 			vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
123591b4e487SEugen Hristev 			isc->cur_frm = NULL;
123691b4e487SEugen Hristev 		}
123791b4e487SEugen Hristev 
123891b4e487SEugen Hristev 		if (!list_empty(&isc->dma_queue) && !isc->stop) {
123991b4e487SEugen Hristev 			isc->cur_frm = list_first_entry(&isc->dma_queue,
124091b4e487SEugen Hristev 							struct isc_buffer, list);
124191b4e487SEugen Hristev 			list_del(&isc->cur_frm->list);
124291b4e487SEugen Hristev 
124391b4e487SEugen Hristev 			isc_start_dma(isc);
124491b4e487SEugen Hristev 		}
124591b4e487SEugen Hristev 
124691b4e487SEugen Hristev 		if (isc->stop)
124791b4e487SEugen Hristev 			complete(&isc->comp);
124891b4e487SEugen Hristev 
124991b4e487SEugen Hristev 		ret = IRQ_HANDLED;
125091b4e487SEugen Hristev 		spin_unlock(&isc->dma_queue_lock);
125191b4e487SEugen Hristev 	}
125291b4e487SEugen Hristev 
125391b4e487SEugen Hristev 	if (pending & ISC_INT_HISDONE) {
125491b4e487SEugen Hristev 		schedule_work(&isc->awb_work);
125591b4e487SEugen Hristev 		ret = IRQ_HANDLED;
125691b4e487SEugen Hristev 	}
125791b4e487SEugen Hristev 
125891b4e487SEugen Hristev 	return ret;
125991b4e487SEugen Hristev }
126091b4e487SEugen Hristev EXPORT_SYMBOL_GPL(microchip_isc_interrupt);
126191b4e487SEugen Hristev 
isc_hist_count(struct isc_device * isc,u32 * min,u32 * max)126291b4e487SEugen Hristev static void isc_hist_count(struct isc_device *isc, u32 *min, u32 *max)
126391b4e487SEugen Hristev {
126491b4e487SEugen Hristev 	struct regmap *regmap = isc->regmap;
126591b4e487SEugen Hristev 	struct isc_ctrls *ctrls = &isc->ctrls;
126691b4e487SEugen Hristev 	u32 *hist_count = &ctrls->hist_count[ctrls->hist_id];
126791b4e487SEugen Hristev 	u32 *hist_entry = &ctrls->hist_entry[0];
126891b4e487SEugen Hristev 	u32 i;
126991b4e487SEugen Hristev 
127091b4e487SEugen Hristev 	*min = 0;
127191b4e487SEugen Hristev 	*max = HIST_ENTRIES;
127291b4e487SEugen Hristev 
127391b4e487SEugen Hristev 	regmap_bulk_read(regmap, ISC_HIS_ENTRY + isc->offsets.his_entry,
127491b4e487SEugen Hristev 			 hist_entry, HIST_ENTRIES);
127591b4e487SEugen Hristev 
127691b4e487SEugen Hristev 	*hist_count = 0;
127791b4e487SEugen Hristev 	/*
127891b4e487SEugen Hristev 	 * we deliberately ignore the end of the histogram,
127991b4e487SEugen Hristev 	 * the most white pixels
128091b4e487SEugen Hristev 	 */
128191b4e487SEugen Hristev 	for (i = 1; i < HIST_ENTRIES; i++) {
128291b4e487SEugen Hristev 		if (*hist_entry && !*min)
128391b4e487SEugen Hristev 			*min = i;
128491b4e487SEugen Hristev 		if (*hist_entry)
128591b4e487SEugen Hristev 			*max = i;
128691b4e487SEugen Hristev 		*hist_count += i * (*hist_entry++);
128791b4e487SEugen Hristev 	}
128891b4e487SEugen Hristev 
128991b4e487SEugen Hristev 	if (!*min)
129091b4e487SEugen Hristev 		*min = 1;
129191b4e487SEugen Hristev 
12928d46c5cdSEugen Hristev 	dev_dbg(isc->dev, "isc wb: hist_id %u, hist_count %u",
129391b4e487SEugen Hristev 		ctrls->hist_id, *hist_count);
129491b4e487SEugen Hristev }
129591b4e487SEugen Hristev 
isc_wb_update(struct isc_ctrls * ctrls)129691b4e487SEugen Hristev static void isc_wb_update(struct isc_ctrls *ctrls)
129791b4e487SEugen Hristev {
129891b4e487SEugen Hristev 	struct isc_device *isc = container_of(ctrls, struct isc_device, ctrls);
129991b4e487SEugen Hristev 	u32 *hist_count = &ctrls->hist_count[0];
130091b4e487SEugen Hristev 	u32 c, offset[4];
130191b4e487SEugen Hristev 	u64 avg = 0;
130291b4e487SEugen Hristev 	/* We compute two gains, stretch gain and grey world gain */
130391b4e487SEugen Hristev 	u32 s_gain[4], gw_gain[4];
130491b4e487SEugen Hristev 
130591b4e487SEugen Hristev 	/*
130691b4e487SEugen Hristev 	 * According to Grey World, we need to set gains for R/B to normalize
130791b4e487SEugen Hristev 	 * them towards the green channel.
130891b4e487SEugen Hristev 	 * Thus we want to keep Green as fixed and adjust only Red/Blue
130991b4e487SEugen Hristev 	 * Compute the average of the both green channels first
131091b4e487SEugen Hristev 	 */
131191b4e487SEugen Hristev 	avg = (u64)hist_count[ISC_HIS_CFG_MODE_GR] +
131291b4e487SEugen Hristev 		(u64)hist_count[ISC_HIS_CFG_MODE_GB];
131391b4e487SEugen Hristev 	avg >>= 1;
131491b4e487SEugen Hristev 
13158d46c5cdSEugen Hristev 	dev_dbg(isc->dev, "isc wb: green components average %llu\n", avg);
131691b4e487SEugen Hristev 
131791b4e487SEugen Hristev 	/* Green histogram is null, nothing to do */
131891b4e487SEugen Hristev 	if (!avg)
131991b4e487SEugen Hristev 		return;
132091b4e487SEugen Hristev 
132191b4e487SEugen Hristev 	for (c = ISC_HIS_CFG_MODE_GR; c <= ISC_HIS_CFG_MODE_B; c++) {
132291b4e487SEugen Hristev 		/*
132391b4e487SEugen Hristev 		 * the color offset is the minimum value of the histogram.
132491b4e487SEugen Hristev 		 * we stretch this color to the full range by substracting
132591b4e487SEugen Hristev 		 * this value from the color component.
132691b4e487SEugen Hristev 		 */
132791b4e487SEugen Hristev 		offset[c] = ctrls->hist_minmax[c][HIST_MIN_INDEX];
132891b4e487SEugen Hristev 		/*
132991b4e487SEugen Hristev 		 * The offset is always at least 1. If the offset is 1, we do
133091b4e487SEugen Hristev 		 * not need to adjust it, so our result must be zero.
133191b4e487SEugen Hristev 		 * the offset is computed in a histogram on 9 bits (0..512)
133291b4e487SEugen Hristev 		 * but the offset in register is based on
133391b4e487SEugen Hristev 		 * 12 bits pipeline (0..4096).
133491b4e487SEugen Hristev 		 * we need to shift with the 3 bits that the histogram is
133591b4e487SEugen Hristev 		 * ignoring
133691b4e487SEugen Hristev 		 */
133791b4e487SEugen Hristev 		ctrls->offset[c] = (offset[c] - 1) << 3;
133891b4e487SEugen Hristev 
133991b4e487SEugen Hristev 		/*
134091b4e487SEugen Hristev 		 * the offset is then taken and converted to 2's complements,
134191b4e487SEugen Hristev 		 * and must be negative, as we subtract this value from the
134291b4e487SEugen Hristev 		 * color components
134391b4e487SEugen Hristev 		 */
134491b4e487SEugen Hristev 		ctrls->offset[c] = -ctrls->offset[c];
134591b4e487SEugen Hristev 
134691b4e487SEugen Hristev 		/*
134791b4e487SEugen Hristev 		 * the stretch gain is the total number of histogram bins
134891b4e487SEugen Hristev 		 * divided by the actual range of color component (Max - Min)
134991b4e487SEugen Hristev 		 * If we compute gain like this, the actual color component
135091b4e487SEugen Hristev 		 * will be stretched to the full histogram.
135191b4e487SEugen Hristev 		 * We need to shift 9 bits for precision, we have 9 bits for
135291b4e487SEugen Hristev 		 * decimals
135391b4e487SEugen Hristev 		 */
135491b4e487SEugen Hristev 		s_gain[c] = (HIST_ENTRIES << 9) /
135591b4e487SEugen Hristev 			(ctrls->hist_minmax[c][HIST_MAX_INDEX] -
135691b4e487SEugen Hristev 			ctrls->hist_minmax[c][HIST_MIN_INDEX] + 1);
135791b4e487SEugen Hristev 
135891b4e487SEugen Hristev 		/*
135991b4e487SEugen Hristev 		 * Now we have to compute the gain w.r.t. the average.
136091b4e487SEugen Hristev 		 * Add/lose gain to the component towards the average.
136191b4e487SEugen Hristev 		 * If it happens that the component is zero, use the
136291b4e487SEugen Hristev 		 * fixed point value : 1.0 gain.
136391b4e487SEugen Hristev 		 */
136491b4e487SEugen Hristev 		if (hist_count[c])
136591b4e487SEugen Hristev 			gw_gain[c] = div_u64(avg << 9, hist_count[c]);
136691b4e487SEugen Hristev 		else
136791b4e487SEugen Hristev 			gw_gain[c] = 1 << 9;
136891b4e487SEugen Hristev 
13698d46c5cdSEugen Hristev 		dev_dbg(isc->dev,
137091b4e487SEugen Hristev 			"isc wb: component %d, s_gain %u, gw_gain %u\n",
137191b4e487SEugen Hristev 			c, s_gain[c], gw_gain[c]);
137291b4e487SEugen Hristev 		/* multiply both gains and adjust for decimals */
137391b4e487SEugen Hristev 		ctrls->gain[c] = s_gain[c] * gw_gain[c];
137491b4e487SEugen Hristev 		ctrls->gain[c] >>= 9;
137591b4e487SEugen Hristev 
137691b4e487SEugen Hristev 		/* make sure we are not out of range */
137791b4e487SEugen Hristev 		ctrls->gain[c] = clamp_val(ctrls->gain[c], 0, GENMASK(12, 0));
137891b4e487SEugen Hristev 
13798d46c5cdSEugen Hristev 		dev_dbg(isc->dev, "isc wb: component %d, final gain %u\n",
138091b4e487SEugen Hristev 			c, ctrls->gain[c]);
138191b4e487SEugen Hristev 	}
138291b4e487SEugen Hristev }
138391b4e487SEugen Hristev 
isc_awb_work(struct work_struct * w)138491b4e487SEugen Hristev static void isc_awb_work(struct work_struct *w)
138591b4e487SEugen Hristev {
138691b4e487SEugen Hristev 	struct isc_device *isc =
138791b4e487SEugen Hristev 		container_of(w, struct isc_device, awb_work);
138891b4e487SEugen Hristev 	struct regmap *regmap = isc->regmap;
138991b4e487SEugen Hristev 	struct isc_ctrls *ctrls = &isc->ctrls;
139091b4e487SEugen Hristev 	u32 hist_id = ctrls->hist_id;
139191b4e487SEugen Hristev 	u32 baysel;
139291b4e487SEugen Hristev 	unsigned long flags;
139391b4e487SEugen Hristev 	u32 min, max;
139491b4e487SEugen Hristev 	int ret;
139591b4e487SEugen Hristev 
139691b4e487SEugen Hristev 	if (ctrls->hist_stat != HIST_ENABLED)
139791b4e487SEugen Hristev 		return;
139891b4e487SEugen Hristev 
139991b4e487SEugen Hristev 	isc_hist_count(isc, &min, &max);
140091b4e487SEugen Hristev 
14018d46c5cdSEugen Hristev 	dev_dbg(isc->dev,
140291b4e487SEugen Hristev 		"isc wb mode %d: hist min %u , max %u\n", hist_id, min, max);
140391b4e487SEugen Hristev 
140491b4e487SEugen Hristev 	ctrls->hist_minmax[hist_id][HIST_MIN_INDEX] = min;
140591b4e487SEugen Hristev 	ctrls->hist_minmax[hist_id][HIST_MAX_INDEX] = max;
140691b4e487SEugen Hristev 
140791b4e487SEugen Hristev 	if (hist_id != ISC_HIS_CFG_MODE_B) {
140891b4e487SEugen Hristev 		hist_id++;
140991b4e487SEugen Hristev 	} else {
141091b4e487SEugen Hristev 		isc_wb_update(ctrls);
141191b4e487SEugen Hristev 		hist_id = ISC_HIS_CFG_MODE_GR;
141291b4e487SEugen Hristev 	}
141391b4e487SEugen Hristev 
141491b4e487SEugen Hristev 	ctrls->hist_id = hist_id;
141591b4e487SEugen Hristev 	baysel = isc->config.sd_format->cfa_baycfg << ISC_HIS_CFG_BAYSEL_SHIFT;
141691b4e487SEugen Hristev 
141791b4e487SEugen Hristev 	ret = pm_runtime_resume_and_get(isc->dev);
141891b4e487SEugen Hristev 	if (ret < 0)
141991b4e487SEugen Hristev 		return;
142091b4e487SEugen Hristev 
142191b4e487SEugen Hristev 	/*
142291b4e487SEugen Hristev 	 * only update if we have all the required histograms and controls
142391b4e487SEugen Hristev 	 * if awb has been disabled, we need to reset registers as well.
142491b4e487SEugen Hristev 	 */
142591b4e487SEugen Hristev 	if (hist_id == ISC_HIS_CFG_MODE_GR || ctrls->awb == ISC_WB_NONE) {
142691b4e487SEugen Hristev 		/*
142791b4e487SEugen Hristev 		 * It may happen that DMA Done IRQ will trigger while we are
142891b4e487SEugen Hristev 		 * updating white balance registers here.
142991b4e487SEugen Hristev 		 * In that case, only parts of the controls have been updated.
143091b4e487SEugen Hristev 		 * We can avoid that by locking the section.
143191b4e487SEugen Hristev 		 */
143291b4e487SEugen Hristev 		spin_lock_irqsave(&isc->awb_lock, flags);
143391b4e487SEugen Hristev 		isc_update_awb_ctrls(isc);
143491b4e487SEugen Hristev 		spin_unlock_irqrestore(&isc->awb_lock, flags);
143591b4e487SEugen Hristev 
143691b4e487SEugen Hristev 		/*
143791b4e487SEugen Hristev 		 * if we are doing just the one time white balance adjustment,
143891b4e487SEugen Hristev 		 * we are basically done.
143991b4e487SEugen Hristev 		 */
144091b4e487SEugen Hristev 		if (ctrls->awb == ISC_WB_ONETIME) {
14418d46c5cdSEugen Hristev 			dev_info(isc->dev,
144291b4e487SEugen Hristev 				 "Completed one time white-balance adjustment.\n");
144391b4e487SEugen Hristev 			/* update the v4l2 controls values */
144491b4e487SEugen Hristev 			isc_update_v4l2_ctrls(isc);
144591b4e487SEugen Hristev 			ctrls->awb = ISC_WB_NONE;
144691b4e487SEugen Hristev 		}
144791b4e487SEugen Hristev 	}
144891b4e487SEugen Hristev 	regmap_write(regmap, ISC_HIS_CFG + isc->offsets.his,
144991b4e487SEugen Hristev 		     hist_id | baysel | ISC_HIS_CFG_RAR);
145091b4e487SEugen Hristev 
145191b4e487SEugen Hristev 	/*
145291b4e487SEugen Hristev 	 * We have to make sure the streaming has not stopped meanwhile.
145391b4e487SEugen Hristev 	 * ISC requires a frame to clock the internal profile update.
145491b4e487SEugen Hristev 	 * To avoid issues, lock the sequence with a mutex
145591b4e487SEugen Hristev 	 */
145691b4e487SEugen Hristev 	mutex_lock(&isc->awb_mutex);
145791b4e487SEugen Hristev 
145891b4e487SEugen Hristev 	/* streaming is not active anymore */
145991b4e487SEugen Hristev 	if (isc->stop) {
146091b4e487SEugen Hristev 		mutex_unlock(&isc->awb_mutex);
146191b4e487SEugen Hristev 		return;
146291b4e487SEugen Hristev 	}
146391b4e487SEugen Hristev 
146491b4e487SEugen Hristev 	isc_update_profile(isc);
146591b4e487SEugen Hristev 
146691b4e487SEugen Hristev 	mutex_unlock(&isc->awb_mutex);
146791b4e487SEugen Hristev 
146891b4e487SEugen Hristev 	/* if awb has been disabled, we don't need to start another histogram */
146991b4e487SEugen Hristev 	if (ctrls->awb)
147091b4e487SEugen Hristev 		regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ);
147191b4e487SEugen Hristev 
147291b4e487SEugen Hristev 	pm_runtime_put_sync(isc->dev);
147391b4e487SEugen Hristev }
147491b4e487SEugen Hristev 
isc_s_ctrl(struct v4l2_ctrl * ctrl)147591b4e487SEugen Hristev static int isc_s_ctrl(struct v4l2_ctrl *ctrl)
147691b4e487SEugen Hristev {
147791b4e487SEugen Hristev 	struct isc_device *isc = container_of(ctrl->handler,
147891b4e487SEugen Hristev 					     struct isc_device, ctrls.handler);
147991b4e487SEugen Hristev 	struct isc_ctrls *ctrls = &isc->ctrls;
148091b4e487SEugen Hristev 
148191b4e487SEugen Hristev 	if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
148291b4e487SEugen Hristev 		return 0;
148391b4e487SEugen Hristev 
148491b4e487SEugen Hristev 	switch (ctrl->id) {
148591b4e487SEugen Hristev 	case V4L2_CID_BRIGHTNESS:
148691b4e487SEugen Hristev 		ctrls->brightness = ctrl->val & ISC_CBC_BRIGHT_MASK;
148791b4e487SEugen Hristev 		break;
148891b4e487SEugen Hristev 	case V4L2_CID_CONTRAST:
148991b4e487SEugen Hristev 		ctrls->contrast = ctrl->val & ISC_CBC_CONTRAST_MASK;
149091b4e487SEugen Hristev 		break;
149191b4e487SEugen Hristev 	case V4L2_CID_GAMMA:
149291b4e487SEugen Hristev 		ctrls->gamma_index = ctrl->val;
149391b4e487SEugen Hristev 		break;
149491b4e487SEugen Hristev 	default:
149591b4e487SEugen Hristev 		return -EINVAL;
149691b4e487SEugen Hristev 	}
149791b4e487SEugen Hristev 
149891b4e487SEugen Hristev 	return 0;
149991b4e487SEugen Hristev }
150091b4e487SEugen Hristev 
150191b4e487SEugen Hristev static const struct v4l2_ctrl_ops isc_ctrl_ops = {
150291b4e487SEugen Hristev 	.s_ctrl	= isc_s_ctrl,
150391b4e487SEugen Hristev };
150491b4e487SEugen Hristev 
isc_s_awb_ctrl(struct v4l2_ctrl * ctrl)150591b4e487SEugen Hristev static int isc_s_awb_ctrl(struct v4l2_ctrl *ctrl)
150691b4e487SEugen Hristev {
150791b4e487SEugen Hristev 	struct isc_device *isc = container_of(ctrl->handler,
150891b4e487SEugen Hristev 					     struct isc_device, ctrls.handler);
150991b4e487SEugen Hristev 	struct isc_ctrls *ctrls = &isc->ctrls;
151091b4e487SEugen Hristev 
151191b4e487SEugen Hristev 	if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
151291b4e487SEugen Hristev 		return 0;
151391b4e487SEugen Hristev 
151491b4e487SEugen Hristev 	switch (ctrl->id) {
151591b4e487SEugen Hristev 	case V4L2_CID_AUTO_WHITE_BALANCE:
151691b4e487SEugen Hristev 		if (ctrl->val == 1)
151791b4e487SEugen Hristev 			ctrls->awb = ISC_WB_AUTO;
151891b4e487SEugen Hristev 		else
151991b4e487SEugen Hristev 			ctrls->awb = ISC_WB_NONE;
152091b4e487SEugen Hristev 
152191b4e487SEugen Hristev 		/* configure the controls with new values from v4l2 */
152291b4e487SEugen Hristev 		if (ctrl->cluster[ISC_CTRL_R_GAIN]->is_new)
152391b4e487SEugen Hristev 			ctrls->gain[ISC_HIS_CFG_MODE_R] = isc->r_gain_ctrl->val;
152491b4e487SEugen Hristev 		if (ctrl->cluster[ISC_CTRL_B_GAIN]->is_new)
152591b4e487SEugen Hristev 			ctrls->gain[ISC_HIS_CFG_MODE_B] = isc->b_gain_ctrl->val;
152691b4e487SEugen Hristev 		if (ctrl->cluster[ISC_CTRL_GR_GAIN]->is_new)
152791b4e487SEugen Hristev 			ctrls->gain[ISC_HIS_CFG_MODE_GR] = isc->gr_gain_ctrl->val;
152891b4e487SEugen Hristev 		if (ctrl->cluster[ISC_CTRL_GB_GAIN]->is_new)
152991b4e487SEugen Hristev 			ctrls->gain[ISC_HIS_CFG_MODE_GB] = isc->gb_gain_ctrl->val;
153091b4e487SEugen Hristev 
153191b4e487SEugen Hristev 		if (ctrl->cluster[ISC_CTRL_R_OFF]->is_new)
153291b4e487SEugen Hristev 			ctrls->offset[ISC_HIS_CFG_MODE_R] = isc->r_off_ctrl->val;
153391b4e487SEugen Hristev 		if (ctrl->cluster[ISC_CTRL_B_OFF]->is_new)
153491b4e487SEugen Hristev 			ctrls->offset[ISC_HIS_CFG_MODE_B] = isc->b_off_ctrl->val;
153591b4e487SEugen Hristev 		if (ctrl->cluster[ISC_CTRL_GR_OFF]->is_new)
153691b4e487SEugen Hristev 			ctrls->offset[ISC_HIS_CFG_MODE_GR] = isc->gr_off_ctrl->val;
153791b4e487SEugen Hristev 		if (ctrl->cluster[ISC_CTRL_GB_OFF]->is_new)
153891b4e487SEugen Hristev 			ctrls->offset[ISC_HIS_CFG_MODE_GB] = isc->gb_off_ctrl->val;
153991b4e487SEugen Hristev 
154091b4e487SEugen Hristev 		isc_update_awb_ctrls(isc);
154191b4e487SEugen Hristev 
154291b4e487SEugen Hristev 		mutex_lock(&isc->awb_mutex);
154391b4e487SEugen Hristev 		if (vb2_is_streaming(&isc->vb2_vidq)) {
154491b4e487SEugen Hristev 			/*
154591b4e487SEugen Hristev 			 * If we are streaming, we can update profile to
154691b4e487SEugen Hristev 			 * have the new settings in place.
154791b4e487SEugen Hristev 			 */
154891b4e487SEugen Hristev 			isc_update_profile(isc);
154991b4e487SEugen Hristev 		} else {
155091b4e487SEugen Hristev 			/*
155191b4e487SEugen Hristev 			 * The auto cluster will activate automatically this
155291b4e487SEugen Hristev 			 * control. This has to be deactivated when not
155391b4e487SEugen Hristev 			 * streaming.
155491b4e487SEugen Hristev 			 */
155591b4e487SEugen Hristev 			v4l2_ctrl_activate(isc->do_wb_ctrl, false);
155691b4e487SEugen Hristev 		}
155791b4e487SEugen Hristev 		mutex_unlock(&isc->awb_mutex);
155891b4e487SEugen Hristev 
155991b4e487SEugen Hristev 		/* if we have autowhitebalance on, start histogram procedure */
156091b4e487SEugen Hristev 		if (ctrls->awb == ISC_WB_AUTO &&
156191b4e487SEugen Hristev 		    vb2_is_streaming(&isc->vb2_vidq) &&
156291b4e487SEugen Hristev 		    ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code))
156391b4e487SEugen Hristev 			isc_set_histogram(isc, true);
156491b4e487SEugen Hristev 
156591b4e487SEugen Hristev 		/*
156691b4e487SEugen Hristev 		 * for one time whitebalance adjustment, check the button,
156791b4e487SEugen Hristev 		 * if it's pressed, perform the one time operation.
156891b4e487SEugen Hristev 		 */
156991b4e487SEugen Hristev 		if (ctrls->awb == ISC_WB_NONE &&
157091b4e487SEugen Hristev 		    ctrl->cluster[ISC_CTRL_DO_WB]->is_new &&
157191b4e487SEugen Hristev 		    !(ctrl->cluster[ISC_CTRL_DO_WB]->flags &
157291b4e487SEugen Hristev 		    V4L2_CTRL_FLAG_INACTIVE)) {
157391b4e487SEugen Hristev 			ctrls->awb = ISC_WB_ONETIME;
157491b4e487SEugen Hristev 			isc_set_histogram(isc, true);
15758d46c5cdSEugen Hristev 			dev_dbg(isc->dev, "One time white-balance started.\n");
157691b4e487SEugen Hristev 		}
157791b4e487SEugen Hristev 		return 0;
157891b4e487SEugen Hristev 	}
157991b4e487SEugen Hristev 	return 0;
158091b4e487SEugen Hristev }
158191b4e487SEugen Hristev 
isc_g_volatile_awb_ctrl(struct v4l2_ctrl * ctrl)158291b4e487SEugen Hristev static int isc_g_volatile_awb_ctrl(struct v4l2_ctrl *ctrl)
158391b4e487SEugen Hristev {
158491b4e487SEugen Hristev 	struct isc_device *isc = container_of(ctrl->handler,
158591b4e487SEugen Hristev 					     struct isc_device, ctrls.handler);
158691b4e487SEugen Hristev 	struct isc_ctrls *ctrls = &isc->ctrls;
158791b4e487SEugen Hristev 
158891b4e487SEugen Hristev 	switch (ctrl->id) {
158991b4e487SEugen Hristev 	/* being a cluster, this id will be called for every control */
159091b4e487SEugen Hristev 	case V4L2_CID_AUTO_WHITE_BALANCE:
159191b4e487SEugen Hristev 		ctrl->cluster[ISC_CTRL_R_GAIN]->val =
159291b4e487SEugen Hristev 					ctrls->gain[ISC_HIS_CFG_MODE_R];
159391b4e487SEugen Hristev 		ctrl->cluster[ISC_CTRL_B_GAIN]->val =
159491b4e487SEugen Hristev 					ctrls->gain[ISC_HIS_CFG_MODE_B];
159591b4e487SEugen Hristev 		ctrl->cluster[ISC_CTRL_GR_GAIN]->val =
159691b4e487SEugen Hristev 					ctrls->gain[ISC_HIS_CFG_MODE_GR];
159791b4e487SEugen Hristev 		ctrl->cluster[ISC_CTRL_GB_GAIN]->val =
159891b4e487SEugen Hristev 					ctrls->gain[ISC_HIS_CFG_MODE_GB];
159991b4e487SEugen Hristev 
160091b4e487SEugen Hristev 		ctrl->cluster[ISC_CTRL_R_OFF]->val =
160191b4e487SEugen Hristev 			ctrls->offset[ISC_HIS_CFG_MODE_R];
160291b4e487SEugen Hristev 		ctrl->cluster[ISC_CTRL_B_OFF]->val =
160391b4e487SEugen Hristev 			ctrls->offset[ISC_HIS_CFG_MODE_B];
160491b4e487SEugen Hristev 		ctrl->cluster[ISC_CTRL_GR_OFF]->val =
160591b4e487SEugen Hristev 			ctrls->offset[ISC_HIS_CFG_MODE_GR];
160691b4e487SEugen Hristev 		ctrl->cluster[ISC_CTRL_GB_OFF]->val =
160791b4e487SEugen Hristev 			ctrls->offset[ISC_HIS_CFG_MODE_GB];
160891b4e487SEugen Hristev 		break;
160991b4e487SEugen Hristev 	}
161091b4e487SEugen Hristev 	return 0;
161191b4e487SEugen Hristev }
161291b4e487SEugen Hristev 
161391b4e487SEugen Hristev static const struct v4l2_ctrl_ops isc_awb_ops = {
161491b4e487SEugen Hristev 	.s_ctrl = isc_s_awb_ctrl,
161591b4e487SEugen Hristev 	.g_volatile_ctrl = isc_g_volatile_awb_ctrl,
161691b4e487SEugen Hristev };
161791b4e487SEugen Hristev 
161891b4e487SEugen Hristev #define ISC_CTRL_OFF(_name, _id, _name_str) \
161991b4e487SEugen Hristev 	static const struct v4l2_ctrl_config _name = { \
162091b4e487SEugen Hristev 		.ops = &isc_awb_ops, \
162191b4e487SEugen Hristev 		.id = _id, \
162291b4e487SEugen Hristev 		.name = _name_str, \
162391b4e487SEugen Hristev 		.type = V4L2_CTRL_TYPE_INTEGER, \
162491b4e487SEugen Hristev 		.flags = V4L2_CTRL_FLAG_SLIDER, \
162591b4e487SEugen Hristev 		.min = -4095, \
162691b4e487SEugen Hristev 		.max = 4095, \
162791b4e487SEugen Hristev 		.step = 1, \
162891b4e487SEugen Hristev 		.def = 0, \
162991b4e487SEugen Hristev 	}
163091b4e487SEugen Hristev 
163191b4e487SEugen Hristev ISC_CTRL_OFF(isc_r_off_ctrl, ISC_CID_R_OFFSET, "Red Component Offset");
163291b4e487SEugen Hristev ISC_CTRL_OFF(isc_b_off_ctrl, ISC_CID_B_OFFSET, "Blue Component Offset");
163391b4e487SEugen Hristev ISC_CTRL_OFF(isc_gr_off_ctrl, ISC_CID_GR_OFFSET, "Green Red Component Offset");
163491b4e487SEugen Hristev ISC_CTRL_OFF(isc_gb_off_ctrl, ISC_CID_GB_OFFSET, "Green Blue Component Offset");
163591b4e487SEugen Hristev 
163691b4e487SEugen Hristev #define ISC_CTRL_GAIN(_name, _id, _name_str) \
163791b4e487SEugen Hristev 	static const struct v4l2_ctrl_config _name = { \
163891b4e487SEugen Hristev 		.ops = &isc_awb_ops, \
163991b4e487SEugen Hristev 		.id = _id, \
164091b4e487SEugen Hristev 		.name = _name_str, \
164191b4e487SEugen Hristev 		.type = V4L2_CTRL_TYPE_INTEGER, \
164291b4e487SEugen Hristev 		.flags = V4L2_CTRL_FLAG_SLIDER, \
164391b4e487SEugen Hristev 		.min = 0, \
164491b4e487SEugen Hristev 		.max = 8191, \
164591b4e487SEugen Hristev 		.step = 1, \
164691b4e487SEugen Hristev 		.def = 512, \
164791b4e487SEugen Hristev 	}
164891b4e487SEugen Hristev 
164991b4e487SEugen Hristev ISC_CTRL_GAIN(isc_r_gain_ctrl, ISC_CID_R_GAIN, "Red Component Gain");
165091b4e487SEugen Hristev ISC_CTRL_GAIN(isc_b_gain_ctrl, ISC_CID_B_GAIN, "Blue Component Gain");
165191b4e487SEugen Hristev ISC_CTRL_GAIN(isc_gr_gain_ctrl, ISC_CID_GR_GAIN, "Green Red Component Gain");
165291b4e487SEugen Hristev ISC_CTRL_GAIN(isc_gb_gain_ctrl, ISC_CID_GB_GAIN, "Green Blue Component Gain");
165391b4e487SEugen Hristev 
isc_ctrl_init(struct isc_device * isc)165491b4e487SEugen Hristev static int isc_ctrl_init(struct isc_device *isc)
165591b4e487SEugen Hristev {
165691b4e487SEugen Hristev 	const struct v4l2_ctrl_ops *ops = &isc_ctrl_ops;
165791b4e487SEugen Hristev 	struct isc_ctrls *ctrls = &isc->ctrls;
165891b4e487SEugen Hristev 	struct v4l2_ctrl_handler *hdl = &ctrls->handler;
165991b4e487SEugen Hristev 	int ret;
166091b4e487SEugen Hristev 
166191b4e487SEugen Hristev 	ctrls->hist_stat = HIST_INIT;
166291b4e487SEugen Hristev 	isc_reset_awb_ctrls(isc);
166391b4e487SEugen Hristev 
166491b4e487SEugen Hristev 	ret = v4l2_ctrl_handler_init(hdl, 13);
166591b4e487SEugen Hristev 	if (ret < 0)
166691b4e487SEugen Hristev 		return ret;
166791b4e487SEugen Hristev 
166891b4e487SEugen Hristev 	/* Initialize product specific controls. For example, contrast */
166991b4e487SEugen Hristev 	isc->config_ctrls(isc, ops);
167091b4e487SEugen Hristev 
167191b4e487SEugen Hristev 	ctrls->brightness = 0;
167291b4e487SEugen Hristev 
167391b4e487SEugen Hristev 	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -1024, 1023, 1, 0);
167491b4e487SEugen Hristev 	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAMMA, 0, isc->gamma_max, 1,
167591b4e487SEugen Hristev 			  isc->gamma_max);
167691b4e487SEugen Hristev 	isc->awb_ctrl = v4l2_ctrl_new_std(hdl, &isc_awb_ops,
167791b4e487SEugen Hristev 					  V4L2_CID_AUTO_WHITE_BALANCE,
167891b4e487SEugen Hristev 					  0, 1, 1, 1);
167991b4e487SEugen Hristev 
168091b4e487SEugen Hristev 	/* do_white_balance is a button, so min,max,step,default are ignored */
168191b4e487SEugen Hristev 	isc->do_wb_ctrl = v4l2_ctrl_new_std(hdl, &isc_awb_ops,
168291b4e487SEugen Hristev 					    V4L2_CID_DO_WHITE_BALANCE,
168391b4e487SEugen Hristev 					    0, 0, 0, 0);
168491b4e487SEugen Hristev 
168591b4e487SEugen Hristev 	if (!isc->do_wb_ctrl) {
168691b4e487SEugen Hristev 		ret = hdl->error;
168791b4e487SEugen Hristev 		v4l2_ctrl_handler_free(hdl);
168891b4e487SEugen Hristev 		return ret;
168991b4e487SEugen Hristev 	}
169091b4e487SEugen Hristev 
169191b4e487SEugen Hristev 	v4l2_ctrl_activate(isc->do_wb_ctrl, false);
169291b4e487SEugen Hristev 
169391b4e487SEugen Hristev 	isc->r_gain_ctrl = v4l2_ctrl_new_custom(hdl, &isc_r_gain_ctrl, NULL);
169491b4e487SEugen Hristev 	isc->b_gain_ctrl = v4l2_ctrl_new_custom(hdl, &isc_b_gain_ctrl, NULL);
169591b4e487SEugen Hristev 	isc->gr_gain_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gr_gain_ctrl, NULL);
169691b4e487SEugen Hristev 	isc->gb_gain_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gb_gain_ctrl, NULL);
169791b4e487SEugen Hristev 	isc->r_off_ctrl = v4l2_ctrl_new_custom(hdl, &isc_r_off_ctrl, NULL);
169891b4e487SEugen Hristev 	isc->b_off_ctrl = v4l2_ctrl_new_custom(hdl, &isc_b_off_ctrl, NULL);
169991b4e487SEugen Hristev 	isc->gr_off_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gr_off_ctrl, NULL);
170091b4e487SEugen Hristev 	isc->gb_off_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gb_off_ctrl, NULL);
170191b4e487SEugen Hristev 
170291b4e487SEugen Hristev 	/*
170391b4e487SEugen Hristev 	 * The cluster is in auto mode with autowhitebalance enabled
170491b4e487SEugen Hristev 	 * and manual mode otherwise.
170591b4e487SEugen Hristev 	 */
170691b4e487SEugen Hristev 	v4l2_ctrl_auto_cluster(10, &isc->awb_ctrl, 0, true);
170791b4e487SEugen Hristev 
170891b4e487SEugen Hristev 	v4l2_ctrl_handler_setup(hdl);
170991b4e487SEugen Hristev 
171091b4e487SEugen Hristev 	return 0;
171191b4e487SEugen Hristev }
171291b4e487SEugen Hristev 
isc_async_bound(struct v4l2_async_notifier * notifier,struct v4l2_subdev * subdev,struct v4l2_async_connection * asd)171391b4e487SEugen Hristev static int isc_async_bound(struct v4l2_async_notifier *notifier,
171491b4e487SEugen Hristev 			   struct v4l2_subdev *subdev,
1715*adb2dcd5SSakari Ailus 			   struct v4l2_async_connection *asd)
171691b4e487SEugen Hristev {
171791b4e487SEugen Hristev 	struct isc_device *isc = container_of(notifier->v4l2_dev,
171891b4e487SEugen Hristev 					      struct isc_device, v4l2_dev);
171991b4e487SEugen Hristev 	struct isc_subdev_entity *subdev_entity =
172091b4e487SEugen Hristev 		container_of(notifier, struct isc_subdev_entity, notifier);
1721920b2665SEugen Hristev 	int pad;
172291b4e487SEugen Hristev 
172391b4e487SEugen Hristev 	if (video_is_registered(&isc->video_dev)) {
17248d46c5cdSEugen Hristev 		dev_err(isc->dev, "only supports one sub-device.\n");
172591b4e487SEugen Hristev 		return -EBUSY;
172691b4e487SEugen Hristev 	}
172791b4e487SEugen Hristev 
172891b4e487SEugen Hristev 	subdev_entity->sd = subdev;
172991b4e487SEugen Hristev 
1730920b2665SEugen Hristev 	pad = media_entity_get_fwnode_pad(&subdev->entity, asd->match.fwnode,
1731920b2665SEugen Hristev 					  MEDIA_PAD_FL_SOURCE);
1732920b2665SEugen Hristev 	if (pad < 0) {
17338d46c5cdSEugen Hristev 		dev_err(isc->dev, "failed to find pad for %s\n", subdev->name);
1734920b2665SEugen Hristev 		return pad;
1735920b2665SEugen Hristev 	}
1736920b2665SEugen Hristev 
1737920b2665SEugen Hristev 	isc->remote_pad = pad;
1738920b2665SEugen Hristev 
173991b4e487SEugen Hristev 	return 0;
174091b4e487SEugen Hristev }
174191b4e487SEugen Hristev 
isc_async_unbind(struct v4l2_async_notifier * notifier,struct v4l2_subdev * subdev,struct v4l2_async_connection * asd)174291b4e487SEugen Hristev static void isc_async_unbind(struct v4l2_async_notifier *notifier,
174391b4e487SEugen Hristev 			     struct v4l2_subdev *subdev,
1744*adb2dcd5SSakari Ailus 			     struct v4l2_async_connection *asd)
174591b4e487SEugen Hristev {
174691b4e487SEugen Hristev 	struct isc_device *isc = container_of(notifier->v4l2_dev,
174791b4e487SEugen Hristev 					      struct isc_device, v4l2_dev);
174891b4e487SEugen Hristev 	mutex_destroy(&isc->awb_mutex);
174991b4e487SEugen Hristev 	cancel_work_sync(&isc->awb_work);
175091b4e487SEugen Hristev 	video_unregister_device(&isc->video_dev);
175191b4e487SEugen Hristev 	v4l2_ctrl_handler_free(&isc->ctrls.handler);
175291b4e487SEugen Hristev }
175391b4e487SEugen Hristev 
isc_find_format_by_code(struct isc_device * isc,unsigned int code,int * index)1754920b2665SEugen Hristev struct isc_format *isc_find_format_by_code(struct isc_device *isc,
175591b4e487SEugen Hristev 					   unsigned int code, int *index)
175691b4e487SEugen Hristev {
175791b4e487SEugen Hristev 	struct isc_format *fmt = &isc->formats_list[0];
175891b4e487SEugen Hristev 	unsigned int i;
175991b4e487SEugen Hristev 
176091b4e487SEugen Hristev 	for (i = 0; i < isc->formats_list_size; i++) {
176191b4e487SEugen Hristev 		if (fmt->mbus_code == code) {
176291b4e487SEugen Hristev 			*index = i;
176391b4e487SEugen Hristev 			return fmt;
176491b4e487SEugen Hristev 		}
176591b4e487SEugen Hristev 
176691b4e487SEugen Hristev 		fmt++;
176791b4e487SEugen Hristev 	}
176891b4e487SEugen Hristev 
176991b4e487SEugen Hristev 	return NULL;
177091b4e487SEugen Hristev }
1771920b2665SEugen Hristev EXPORT_SYMBOL_GPL(isc_find_format_by_code);
177291b4e487SEugen Hristev 
isc_set_default_fmt(struct isc_device * isc)177391b4e487SEugen Hristev static int isc_set_default_fmt(struct isc_device *isc)
177491b4e487SEugen Hristev {
177591b4e487SEugen Hristev 	struct v4l2_format f = {
177691b4e487SEugen Hristev 		.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
177791b4e487SEugen Hristev 		.fmt.pix = {
177891b4e487SEugen Hristev 			.width		= VGA_WIDTH,
177991b4e487SEugen Hristev 			.height		= VGA_HEIGHT,
178091b4e487SEugen Hristev 			.field		= V4L2_FIELD_NONE,
178178ba0d79SEugen Hristev 			.pixelformat	= isc->controller_formats[0].fourcc,
178291b4e487SEugen Hristev 		},
178391b4e487SEugen Hristev 	};
178491b4e487SEugen Hristev 	int ret;
178591b4e487SEugen Hristev 
178678ba0d79SEugen Hristev 	ret = isc_try_fmt(isc, &f);
178791b4e487SEugen Hristev 	if (ret)
178891b4e487SEugen Hristev 		return ret;
178991b4e487SEugen Hristev 
179091b4e487SEugen Hristev 	isc->fmt = f;
179191b4e487SEugen Hristev 	return 0;
179291b4e487SEugen Hristev }
179391b4e487SEugen Hristev 
isc_async_complete(struct v4l2_async_notifier * notifier)179491b4e487SEugen Hristev static int isc_async_complete(struct v4l2_async_notifier *notifier)
179591b4e487SEugen Hristev {
179691b4e487SEugen Hristev 	struct isc_device *isc = container_of(notifier->v4l2_dev,
179791b4e487SEugen Hristev 					      struct isc_device, v4l2_dev);
179891b4e487SEugen Hristev 	struct video_device *vdev = &isc->video_dev;
179991b4e487SEugen Hristev 	struct vb2_queue *q = &isc->vb2_vidq;
180091b4e487SEugen Hristev 	int ret = 0;
180191b4e487SEugen Hristev 
180291b4e487SEugen Hristev 	INIT_WORK(&isc->awb_work, isc_awb_work);
180391b4e487SEugen Hristev 
180491b4e487SEugen Hristev 	ret = v4l2_device_register_subdev_nodes(&isc->v4l2_dev);
180591b4e487SEugen Hristev 	if (ret < 0) {
18068d46c5cdSEugen Hristev 		dev_err(isc->dev, "Failed to register subdev nodes\n");
180791b4e487SEugen Hristev 		return ret;
180891b4e487SEugen Hristev 	}
180991b4e487SEugen Hristev 
181091b4e487SEugen Hristev 	isc->current_subdev = container_of(notifier,
181191b4e487SEugen Hristev 					   struct isc_subdev_entity, notifier);
181291b4e487SEugen Hristev 	mutex_init(&isc->lock);
181391b4e487SEugen Hristev 	mutex_init(&isc->awb_mutex);
181491b4e487SEugen Hristev 
181591b4e487SEugen Hristev 	init_completion(&isc->comp);
181691b4e487SEugen Hristev 
181791b4e487SEugen Hristev 	/* Initialize videobuf2 queue */
181891b4e487SEugen Hristev 	q->type			= V4L2_BUF_TYPE_VIDEO_CAPTURE;
181991b4e487SEugen Hristev 	q->io_modes		= VB2_MMAP | VB2_DMABUF | VB2_READ;
182091b4e487SEugen Hristev 	q->drv_priv		= isc;
182191b4e487SEugen Hristev 	q->buf_struct_size	= sizeof(struct isc_buffer);
182291b4e487SEugen Hristev 	q->ops			= &isc_vb2_ops;
182391b4e487SEugen Hristev 	q->mem_ops		= &vb2_dma_contig_memops;
182491b4e487SEugen Hristev 	q->timestamp_flags	= V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
182591b4e487SEugen Hristev 	q->lock			= &isc->lock;
182691b4e487SEugen Hristev 	q->min_buffers_needed	= 1;
182791b4e487SEugen Hristev 	q->dev			= isc->dev;
182891b4e487SEugen Hristev 
182991b4e487SEugen Hristev 	ret = vb2_queue_init(q);
183091b4e487SEugen Hristev 	if (ret < 0) {
18318d46c5cdSEugen Hristev 		dev_err(isc->dev, "vb2_queue_init() failed: %d\n", ret);
183291b4e487SEugen Hristev 		goto isc_async_complete_err;
183391b4e487SEugen Hristev 	}
183491b4e487SEugen Hristev 
183591b4e487SEugen Hristev 	/* Init video dma queues */
183691b4e487SEugen Hristev 	INIT_LIST_HEAD(&isc->dma_queue);
183791b4e487SEugen Hristev 	spin_lock_init(&isc->dma_queue_lock);
183891b4e487SEugen Hristev 	spin_lock_init(&isc->awb_lock);
183991b4e487SEugen Hristev 
184091b4e487SEugen Hristev 	ret = isc_set_default_fmt(isc);
184191b4e487SEugen Hristev 	if (ret) {
18428d46c5cdSEugen Hristev 		dev_err(isc->dev, "Could not set default format\n");
184391b4e487SEugen Hristev 		goto isc_async_complete_err;
184491b4e487SEugen Hristev 	}
184591b4e487SEugen Hristev 
184691b4e487SEugen Hristev 	ret = isc_ctrl_init(isc);
184791b4e487SEugen Hristev 	if (ret) {
18488d46c5cdSEugen Hristev 		dev_err(isc->dev, "Init isc ctrols failed: %d\n", ret);
184991b4e487SEugen Hristev 		goto isc_async_complete_err;
185091b4e487SEugen Hristev 	}
185191b4e487SEugen Hristev 
185291b4e487SEugen Hristev 	/* Register video device */
185391b4e487SEugen Hristev 	strscpy(vdev->name, KBUILD_MODNAME, sizeof(vdev->name));
185491b4e487SEugen Hristev 	vdev->release		= video_device_release_empty;
185591b4e487SEugen Hristev 	vdev->fops		= &isc_fops;
185691b4e487SEugen Hristev 	vdev->ioctl_ops		= &isc_ioctl_ops;
185791b4e487SEugen Hristev 	vdev->v4l2_dev		= &isc->v4l2_dev;
185891b4e487SEugen Hristev 	vdev->vfl_dir		= VFL_DIR_RX;
185991b4e487SEugen Hristev 	vdev->queue		= q;
186091b4e487SEugen Hristev 	vdev->lock		= &isc->lock;
186191b4e487SEugen Hristev 	vdev->ctrl_handler	= &isc->ctrls.handler;
186278ba0d79SEugen Hristev 	vdev->device_caps	= V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE |
186378ba0d79SEugen Hristev 				  V4L2_CAP_IO_MC;
186491b4e487SEugen Hristev 	video_set_drvdata(vdev, isc);
186591b4e487SEugen Hristev 
186691b4e487SEugen Hristev 	ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
186791b4e487SEugen Hristev 	if (ret < 0) {
18688d46c5cdSEugen Hristev 		dev_err(isc->dev, "video_register_device failed: %d\n", ret);
186991b4e487SEugen Hristev 		goto isc_async_complete_err;
187091b4e487SEugen Hristev 	}
187191b4e487SEugen Hristev 
1872920b2665SEugen Hristev 	ret = isc_scaler_link(isc);
1873920b2665SEugen Hristev 	if (ret < 0)
1874920b2665SEugen Hristev 		goto isc_async_complete_unregister_device;
1875920b2665SEugen Hristev 
1876920b2665SEugen Hristev 	ret = media_device_register(&isc->mdev);
1877920b2665SEugen Hristev 	if (ret < 0)
1878920b2665SEugen Hristev 		goto isc_async_complete_unregister_device;
1879920b2665SEugen Hristev 
188091b4e487SEugen Hristev 	return 0;
188191b4e487SEugen Hristev 
1882920b2665SEugen Hristev isc_async_complete_unregister_device:
1883920b2665SEugen Hristev 	video_unregister_device(vdev);
1884920b2665SEugen Hristev 
188591b4e487SEugen Hristev isc_async_complete_err:
188691b4e487SEugen Hristev 	mutex_destroy(&isc->awb_mutex);
188791b4e487SEugen Hristev 	mutex_destroy(&isc->lock);
188891b4e487SEugen Hristev 	return ret;
188991b4e487SEugen Hristev }
189091b4e487SEugen Hristev 
189191b4e487SEugen Hristev const struct v4l2_async_notifier_operations microchip_isc_async_ops = {
189291b4e487SEugen Hristev 	.bound = isc_async_bound,
189391b4e487SEugen Hristev 	.unbind = isc_async_unbind,
189491b4e487SEugen Hristev 	.complete = isc_async_complete,
189591b4e487SEugen Hristev };
189691b4e487SEugen Hristev EXPORT_SYMBOL_GPL(microchip_isc_async_ops);
189791b4e487SEugen Hristev 
microchip_isc_subdev_cleanup(struct isc_device * isc)189891b4e487SEugen Hristev void microchip_isc_subdev_cleanup(struct isc_device *isc)
189991b4e487SEugen Hristev {
190091b4e487SEugen Hristev 	struct isc_subdev_entity *subdev_entity;
190191b4e487SEugen Hristev 
190291b4e487SEugen Hristev 	list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
190391b4e487SEugen Hristev 		v4l2_async_nf_unregister(&subdev_entity->notifier);
190491b4e487SEugen Hristev 		v4l2_async_nf_cleanup(&subdev_entity->notifier);
190591b4e487SEugen Hristev 	}
190691b4e487SEugen Hristev 
190791b4e487SEugen Hristev 	INIT_LIST_HEAD(&isc->subdev_entities);
190891b4e487SEugen Hristev }
190991b4e487SEugen Hristev EXPORT_SYMBOL_GPL(microchip_isc_subdev_cleanup);
191091b4e487SEugen Hristev 
microchip_isc_pipeline_init(struct isc_device * isc)191191b4e487SEugen Hristev int microchip_isc_pipeline_init(struct isc_device *isc)
191291b4e487SEugen Hristev {
191391b4e487SEugen Hristev 	struct device *dev = isc->dev;
191491b4e487SEugen Hristev 	struct regmap *regmap = isc->regmap;
191591b4e487SEugen Hristev 	struct regmap_field *regs;
191691b4e487SEugen Hristev 	unsigned int i;
191791b4e487SEugen Hristev 
191891b4e487SEugen Hristev 	/*
191991b4e487SEugen Hristev 	 * DPCEN-->GDCEN-->BLCEN-->WB-->CFA-->CC-->
192091b4e487SEugen Hristev 	 * GAM-->VHXS-->CSC-->CBC-->SUB422-->SUB420
192191b4e487SEugen Hristev 	 */
192291b4e487SEugen Hristev 	const struct reg_field regfields[ISC_PIPE_LINE_NODE_NUM] = {
192391b4e487SEugen Hristev 		REG_FIELD(ISC_DPC_CTRL, 0, 0),
192491b4e487SEugen Hristev 		REG_FIELD(ISC_DPC_CTRL, 1, 1),
192591b4e487SEugen Hristev 		REG_FIELD(ISC_DPC_CTRL, 2, 2),
192691b4e487SEugen Hristev 		REG_FIELD(ISC_WB_CTRL, 0, 0),
192791b4e487SEugen Hristev 		REG_FIELD(ISC_CFA_CTRL, 0, 0),
192891b4e487SEugen Hristev 		REG_FIELD(ISC_CC_CTRL, 0, 0),
192991b4e487SEugen Hristev 		REG_FIELD(ISC_GAM_CTRL, 0, 0),
193091b4e487SEugen Hristev 		REG_FIELD(ISC_GAM_CTRL, 1, 1),
193191b4e487SEugen Hristev 		REG_FIELD(ISC_GAM_CTRL, 2, 2),
193291b4e487SEugen Hristev 		REG_FIELD(ISC_GAM_CTRL, 3, 3),
193391b4e487SEugen Hristev 		REG_FIELD(ISC_VHXS_CTRL, 0, 0),
193491b4e487SEugen Hristev 		REG_FIELD(ISC_CSC_CTRL + isc->offsets.csc, 0, 0),
193591b4e487SEugen Hristev 		REG_FIELD(ISC_CBC_CTRL + isc->offsets.cbc, 0, 0),
193691b4e487SEugen Hristev 		REG_FIELD(ISC_SUB422_CTRL + isc->offsets.sub422, 0, 0),
193791b4e487SEugen Hristev 		REG_FIELD(ISC_SUB420_CTRL + isc->offsets.sub420, 0, 0),
193891b4e487SEugen Hristev 	};
193991b4e487SEugen Hristev 
194091b4e487SEugen Hristev 	for (i = 0; i < ISC_PIPE_LINE_NODE_NUM; i++) {
194191b4e487SEugen Hristev 		regs = devm_regmap_field_alloc(dev, regmap, regfields[i]);
194291b4e487SEugen Hristev 		if (IS_ERR(regs))
194391b4e487SEugen Hristev 			return PTR_ERR(regs);
194491b4e487SEugen Hristev 
194591b4e487SEugen Hristev 		isc->pipeline[i] =  regs;
194691b4e487SEugen Hristev 	}
194791b4e487SEugen Hristev 
194891b4e487SEugen Hristev 	return 0;
194991b4e487SEugen Hristev }
195091b4e487SEugen Hristev EXPORT_SYMBOL_GPL(microchip_isc_pipeline_init);
195191b4e487SEugen Hristev 
isc_link_validate(struct media_link * link)195278ba0d79SEugen Hristev static int isc_link_validate(struct media_link *link)
195378ba0d79SEugen Hristev {
195478ba0d79SEugen Hristev 	struct video_device *vdev =
195578ba0d79SEugen Hristev 		media_entity_to_video_device(link->sink->entity);
195678ba0d79SEugen Hristev 	struct isc_device *isc = video_get_drvdata(vdev);
195778ba0d79SEugen Hristev 	int ret;
195878ba0d79SEugen Hristev 
195978ba0d79SEugen Hristev 	ret = v4l2_subdev_link_validate(link);
196078ba0d79SEugen Hristev 	if (ret)
196178ba0d79SEugen Hristev 		return ret;
196278ba0d79SEugen Hristev 
196378ba0d79SEugen Hristev 	return isc_validate(isc);
196478ba0d79SEugen Hristev }
196578ba0d79SEugen Hristev 
196678ba0d79SEugen Hristev static const struct media_entity_operations isc_entity_operations = {
196778ba0d79SEugen Hristev 	.link_validate = isc_link_validate,
196878ba0d79SEugen Hristev };
196978ba0d79SEugen Hristev 
isc_mc_init(struct isc_device * isc,u32 ver)1970920b2665SEugen Hristev int isc_mc_init(struct isc_device *isc, u32 ver)
1971920b2665SEugen Hristev {
1972920b2665SEugen Hristev 	const struct of_device_id *match;
1973920b2665SEugen Hristev 	int ret;
1974920b2665SEugen Hristev 
1975920b2665SEugen Hristev 	isc->video_dev.entity.function = MEDIA_ENT_F_IO_V4L;
1976920b2665SEugen Hristev 	isc->video_dev.entity.flags = MEDIA_ENT_FL_DEFAULT;
197778ba0d79SEugen Hristev 	isc->video_dev.entity.ops = &isc_entity_operations;
197878ba0d79SEugen Hristev 
1979920b2665SEugen Hristev 	isc->pads[ISC_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
1980920b2665SEugen Hristev 
1981920b2665SEugen Hristev 	ret = media_entity_pads_init(&isc->video_dev.entity, ISC_PADS_NUM,
1982920b2665SEugen Hristev 				     isc->pads);
1983920b2665SEugen Hristev 	if (ret < 0) {
1984920b2665SEugen Hristev 		dev_err(isc->dev, "media entity init failed\n");
1985920b2665SEugen Hristev 		return ret;
1986920b2665SEugen Hristev 	}
1987920b2665SEugen Hristev 
1988920b2665SEugen Hristev 	isc->mdev.dev = isc->dev;
1989920b2665SEugen Hristev 
1990920b2665SEugen Hristev 	match = of_match_node(isc->dev->driver->of_match_table,
1991920b2665SEugen Hristev 			      isc->dev->of_node);
1992920b2665SEugen Hristev 
1993920b2665SEugen Hristev 	strscpy(isc->mdev.driver_name, KBUILD_MODNAME,
1994920b2665SEugen Hristev 		sizeof(isc->mdev.driver_name));
1995920b2665SEugen Hristev 	strscpy(isc->mdev.model, match->compatible, sizeof(isc->mdev.model));
1996920b2665SEugen Hristev 	snprintf(isc->mdev.bus_info, sizeof(isc->mdev.bus_info), "platform:%s",
1997920b2665SEugen Hristev 		 isc->v4l2_dev.name);
1998920b2665SEugen Hristev 	isc->mdev.hw_revision = ver;
1999920b2665SEugen Hristev 
2000920b2665SEugen Hristev 	media_device_init(&isc->mdev);
2001920b2665SEugen Hristev 
2002920b2665SEugen Hristev 	isc->v4l2_dev.mdev = &isc->mdev;
2003920b2665SEugen Hristev 
2004920b2665SEugen Hristev 	return isc_scaler_init(isc);
2005920b2665SEugen Hristev }
2006920b2665SEugen Hristev EXPORT_SYMBOL_GPL(isc_mc_init);
2007920b2665SEugen Hristev 
isc_mc_cleanup(struct isc_device * isc)2008920b2665SEugen Hristev void isc_mc_cleanup(struct isc_device *isc)
2009920b2665SEugen Hristev {
2010920b2665SEugen Hristev 	media_entity_cleanup(&isc->video_dev.entity);
2011920b2665SEugen Hristev 	media_device_cleanup(&isc->mdev);
2012920b2665SEugen Hristev }
2013920b2665SEugen Hristev EXPORT_SYMBOL_GPL(isc_mc_cleanup);
2014920b2665SEugen Hristev 
201591b4e487SEugen Hristev /* regmap configuration */
201691b4e487SEugen Hristev #define MICROCHIP_ISC_REG_MAX    0xd5c
201791b4e487SEugen Hristev const struct regmap_config microchip_isc_regmap_config = {
201891b4e487SEugen Hristev 	.reg_bits       = 32,
201991b4e487SEugen Hristev 	.reg_stride     = 4,
202091b4e487SEugen Hristev 	.val_bits       = 32,
202191b4e487SEugen Hristev 	.max_register	= MICROCHIP_ISC_REG_MAX,
202291b4e487SEugen Hristev };
202391b4e487SEugen Hristev EXPORT_SYMBOL_GPL(microchip_isc_regmap_config);
202491b4e487SEugen Hristev 
202591b4e487SEugen Hristev MODULE_AUTHOR("Songjun Wu");
202691b4e487SEugen Hristev MODULE_AUTHOR("Eugen Hristev");
202791b4e487SEugen Hristev MODULE_DESCRIPTION("Microchip ISC common code base");
202891b4e487SEugen Hristev MODULE_LICENSE("GPL v2");
2029