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 static unsigned int debug;
3691b4e487SEugen Hristev module_param(debug, int, 0644);
3791b4e487SEugen Hristev MODULE_PARM_DESC(debug, "debug level (0-2)");
3891b4e487SEugen Hristev 
3991b4e487SEugen Hristev static unsigned int sensor_preferred = 1;
4091b4e487SEugen Hristev module_param(sensor_preferred, uint, 0644);
4191b4e487SEugen Hristev MODULE_PARM_DESC(sensor_preferred,
4291b4e487SEugen Hristev 		 "Sensor is preferred to output the specified format (1-on 0-off), default 1");
4391b4e487SEugen Hristev 
4491b4e487SEugen Hristev #define ISC_IS_FORMAT_RAW(mbus_code) \
4591b4e487SEugen Hristev 	(((mbus_code) & 0xf000) == 0x3000)
4691b4e487SEugen Hristev 
4791b4e487SEugen Hristev #define ISC_IS_FORMAT_GREY(mbus_code) \
4891b4e487SEugen Hristev 	(((mbus_code) == MEDIA_BUS_FMT_Y10_1X10) | \
4991b4e487SEugen Hristev 	(((mbus_code) == MEDIA_BUS_FMT_Y8_1X8)))
5091b4e487SEugen Hristev 
5191b4e487SEugen Hristev static inline void isc_update_v4l2_ctrls(struct isc_device *isc)
5291b4e487SEugen Hristev {
5391b4e487SEugen Hristev 	struct isc_ctrls *ctrls = &isc->ctrls;
5491b4e487SEugen Hristev 
5591b4e487SEugen Hristev 	/* In here we set the v4l2 controls w.r.t. our pipeline config */
5691b4e487SEugen Hristev 	v4l2_ctrl_s_ctrl(isc->r_gain_ctrl, ctrls->gain[ISC_HIS_CFG_MODE_R]);
5791b4e487SEugen Hristev 	v4l2_ctrl_s_ctrl(isc->b_gain_ctrl, ctrls->gain[ISC_HIS_CFG_MODE_B]);
5891b4e487SEugen Hristev 	v4l2_ctrl_s_ctrl(isc->gr_gain_ctrl, ctrls->gain[ISC_HIS_CFG_MODE_GR]);
5991b4e487SEugen Hristev 	v4l2_ctrl_s_ctrl(isc->gb_gain_ctrl, ctrls->gain[ISC_HIS_CFG_MODE_GB]);
6091b4e487SEugen Hristev 
6191b4e487SEugen Hristev 	v4l2_ctrl_s_ctrl(isc->r_off_ctrl, ctrls->offset[ISC_HIS_CFG_MODE_R]);
6291b4e487SEugen Hristev 	v4l2_ctrl_s_ctrl(isc->b_off_ctrl, ctrls->offset[ISC_HIS_CFG_MODE_B]);
6391b4e487SEugen Hristev 	v4l2_ctrl_s_ctrl(isc->gr_off_ctrl, ctrls->offset[ISC_HIS_CFG_MODE_GR]);
6491b4e487SEugen Hristev 	v4l2_ctrl_s_ctrl(isc->gb_off_ctrl, ctrls->offset[ISC_HIS_CFG_MODE_GB]);
6591b4e487SEugen Hristev }
6691b4e487SEugen Hristev 
6791b4e487SEugen Hristev static inline void isc_update_awb_ctrls(struct isc_device *isc)
6891b4e487SEugen Hristev {
6991b4e487SEugen Hristev 	struct isc_ctrls *ctrls = &isc->ctrls;
7091b4e487SEugen Hristev 
7191b4e487SEugen Hristev 	/* In here we set our actual hw pipeline config */
7291b4e487SEugen Hristev 
7391b4e487SEugen Hristev 	regmap_write(isc->regmap, ISC_WB_O_RGR,
7491b4e487SEugen Hristev 		     ((ctrls->offset[ISC_HIS_CFG_MODE_R])) |
7591b4e487SEugen Hristev 		     ((ctrls->offset[ISC_HIS_CFG_MODE_GR]) << 16));
7691b4e487SEugen Hristev 	regmap_write(isc->regmap, ISC_WB_O_BGB,
7791b4e487SEugen Hristev 		     ((ctrls->offset[ISC_HIS_CFG_MODE_B])) |
7891b4e487SEugen Hristev 		     ((ctrls->offset[ISC_HIS_CFG_MODE_GB]) << 16));
7991b4e487SEugen Hristev 	regmap_write(isc->regmap, ISC_WB_G_RGR,
8091b4e487SEugen Hristev 		     ctrls->gain[ISC_HIS_CFG_MODE_R] |
8191b4e487SEugen Hristev 		     (ctrls->gain[ISC_HIS_CFG_MODE_GR] << 16));
8291b4e487SEugen Hristev 	regmap_write(isc->regmap, ISC_WB_G_BGB,
8391b4e487SEugen Hristev 		     ctrls->gain[ISC_HIS_CFG_MODE_B] |
8491b4e487SEugen Hristev 		     (ctrls->gain[ISC_HIS_CFG_MODE_GB] << 16));
8591b4e487SEugen Hristev }
8691b4e487SEugen Hristev 
8791b4e487SEugen Hristev static inline void isc_reset_awb_ctrls(struct isc_device *isc)
8891b4e487SEugen Hristev {
8991b4e487SEugen Hristev 	unsigned int c;
9091b4e487SEugen Hristev 
9191b4e487SEugen Hristev 	for (c = ISC_HIS_CFG_MODE_GR; c <= ISC_HIS_CFG_MODE_B; c++) {
9291b4e487SEugen Hristev 		/* gains have a fixed point at 9 decimals */
9391b4e487SEugen Hristev 		isc->ctrls.gain[c] = 1 << 9;
9491b4e487SEugen Hristev 		/* offsets are in 2's complements */
9591b4e487SEugen Hristev 		isc->ctrls.offset[c] = 0;
9691b4e487SEugen Hristev 	}
9791b4e487SEugen Hristev }
9891b4e487SEugen Hristev 
9991b4e487SEugen Hristev static int isc_queue_setup(struct vb2_queue *vq,
10091b4e487SEugen Hristev 			   unsigned int *nbuffers, unsigned int *nplanes,
10191b4e487SEugen Hristev 			   unsigned int sizes[], struct device *alloc_devs[])
10291b4e487SEugen Hristev {
10391b4e487SEugen Hristev 	struct isc_device *isc = vb2_get_drv_priv(vq);
10491b4e487SEugen Hristev 	unsigned int size = isc->fmt.fmt.pix.sizeimage;
10591b4e487SEugen Hristev 
10691b4e487SEugen Hristev 	if (*nplanes)
10791b4e487SEugen Hristev 		return sizes[0] < size ? -EINVAL : 0;
10891b4e487SEugen Hristev 
10991b4e487SEugen Hristev 	*nplanes = 1;
11091b4e487SEugen Hristev 	sizes[0] = size;
11191b4e487SEugen Hristev 
11291b4e487SEugen Hristev 	return 0;
11391b4e487SEugen Hristev }
11491b4e487SEugen Hristev 
11591b4e487SEugen Hristev static int isc_buffer_prepare(struct vb2_buffer *vb)
11691b4e487SEugen Hristev {
11791b4e487SEugen Hristev 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
11891b4e487SEugen Hristev 	struct isc_device *isc = vb2_get_drv_priv(vb->vb2_queue);
11991b4e487SEugen Hristev 	unsigned long size = isc->fmt.fmt.pix.sizeimage;
12091b4e487SEugen Hristev 
12191b4e487SEugen Hristev 	if (vb2_plane_size(vb, 0) < size) {
12291b4e487SEugen Hristev 		v4l2_err(&isc->v4l2_dev, "buffer too small (%lu < %lu)\n",
12391b4e487SEugen Hristev 			 vb2_plane_size(vb, 0), size);
12491b4e487SEugen Hristev 		return -EINVAL;
12591b4e487SEugen Hristev 	}
12691b4e487SEugen Hristev 
12791b4e487SEugen Hristev 	vb2_set_plane_payload(vb, 0, size);
12891b4e487SEugen Hristev 
12991b4e487SEugen Hristev 	vbuf->field = isc->fmt.fmt.pix.field;
13091b4e487SEugen Hristev 
13191b4e487SEugen Hristev 	return 0;
13291b4e487SEugen Hristev }
13391b4e487SEugen Hristev 
13491b4e487SEugen Hristev static void isc_crop_pfe(struct isc_device *isc)
13591b4e487SEugen Hristev {
13691b4e487SEugen Hristev 	struct regmap *regmap = isc->regmap;
13791b4e487SEugen Hristev 	u32 h, w;
13891b4e487SEugen Hristev 
13991b4e487SEugen Hristev 	h = isc->fmt.fmt.pix.height;
14091b4e487SEugen Hristev 	w = isc->fmt.fmt.pix.width;
14191b4e487SEugen Hristev 
14291b4e487SEugen Hristev 	/*
14391b4e487SEugen Hristev 	 * In case the sensor is not RAW, it will output a pixel (12-16 bits)
14491b4e487SEugen Hristev 	 * with two samples on the ISC Data bus (which is 8-12)
14591b4e487SEugen Hristev 	 * ISC will count each sample, so, we need to multiply these values
14691b4e487SEugen Hristev 	 * by two, to get the real number of samples for the required pixels.
14791b4e487SEugen Hristev 	 */
14891b4e487SEugen Hristev 	if (!ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code)) {
14991b4e487SEugen Hristev 		h <<= 1;
15091b4e487SEugen Hristev 		w <<= 1;
15191b4e487SEugen Hristev 	}
15291b4e487SEugen Hristev 
15391b4e487SEugen Hristev 	/*
15491b4e487SEugen Hristev 	 * We limit the column/row count that the ISC will output according
15591b4e487SEugen Hristev 	 * to the configured resolution that we want.
15691b4e487SEugen Hristev 	 * This will avoid the situation where the sensor is misconfigured,
15791b4e487SEugen Hristev 	 * sending more data, and the ISC will just take it and DMA to memory,
15891b4e487SEugen Hristev 	 * causing corruption.
15991b4e487SEugen Hristev 	 */
16091b4e487SEugen Hristev 	regmap_write(regmap, ISC_PFE_CFG1,
16191b4e487SEugen Hristev 		     (ISC_PFE_CFG1_COLMIN(0) & ISC_PFE_CFG1_COLMIN_MASK) |
16291b4e487SEugen Hristev 		     (ISC_PFE_CFG1_COLMAX(w - 1) & ISC_PFE_CFG1_COLMAX_MASK));
16391b4e487SEugen Hristev 
16491b4e487SEugen Hristev 	regmap_write(regmap, ISC_PFE_CFG2,
16591b4e487SEugen Hristev 		     (ISC_PFE_CFG2_ROWMIN(0) & ISC_PFE_CFG2_ROWMIN_MASK) |
16691b4e487SEugen Hristev 		     (ISC_PFE_CFG2_ROWMAX(h - 1) & ISC_PFE_CFG2_ROWMAX_MASK));
16791b4e487SEugen Hristev 
16891b4e487SEugen Hristev 	regmap_update_bits(regmap, ISC_PFE_CFG0,
16991b4e487SEugen Hristev 			   ISC_PFE_CFG0_COLEN | ISC_PFE_CFG0_ROWEN,
17091b4e487SEugen Hristev 			   ISC_PFE_CFG0_COLEN | ISC_PFE_CFG0_ROWEN);
17191b4e487SEugen Hristev }
17291b4e487SEugen Hristev 
17391b4e487SEugen Hristev static void isc_start_dma(struct isc_device *isc)
17491b4e487SEugen Hristev {
17591b4e487SEugen Hristev 	struct regmap *regmap = isc->regmap;
17691b4e487SEugen Hristev 	u32 sizeimage = isc->fmt.fmt.pix.sizeimage;
17791b4e487SEugen Hristev 	u32 dctrl_dview;
17891b4e487SEugen Hristev 	dma_addr_t addr0;
17991b4e487SEugen Hristev 
18091b4e487SEugen Hristev 	addr0 = vb2_dma_contig_plane_dma_addr(&isc->cur_frm->vb.vb2_buf, 0);
18191b4e487SEugen Hristev 	regmap_write(regmap, ISC_DAD0 + isc->offsets.dma, addr0);
18291b4e487SEugen Hristev 
18391b4e487SEugen Hristev 	switch (isc->config.fourcc) {
18491b4e487SEugen Hristev 	case V4L2_PIX_FMT_YUV420:
18591b4e487SEugen Hristev 		regmap_write(regmap, ISC_DAD1 + isc->offsets.dma,
18691b4e487SEugen Hristev 			     addr0 + (sizeimage * 2) / 3);
18791b4e487SEugen Hristev 		regmap_write(regmap, ISC_DAD2 + isc->offsets.dma,
18891b4e487SEugen Hristev 			     addr0 + (sizeimage * 5) / 6);
18991b4e487SEugen Hristev 		break;
19091b4e487SEugen Hristev 	case V4L2_PIX_FMT_YUV422P:
19191b4e487SEugen Hristev 		regmap_write(regmap, ISC_DAD1 + isc->offsets.dma,
19291b4e487SEugen Hristev 			     addr0 + sizeimage / 2);
19391b4e487SEugen Hristev 		regmap_write(regmap, ISC_DAD2 + isc->offsets.dma,
19491b4e487SEugen Hristev 			     addr0 + (sizeimage * 3) / 4);
19591b4e487SEugen Hristev 		break;
19691b4e487SEugen Hristev 	default:
19791b4e487SEugen Hristev 		break;
19891b4e487SEugen Hristev 	}
19991b4e487SEugen Hristev 
20091b4e487SEugen Hristev 	dctrl_dview = isc->config.dctrl_dview;
20191b4e487SEugen Hristev 
20291b4e487SEugen Hristev 	regmap_write(regmap, ISC_DCTRL + isc->offsets.dma,
20391b4e487SEugen Hristev 		     dctrl_dview | ISC_DCTRL_IE_IS);
20491b4e487SEugen Hristev 	spin_lock(&isc->awb_lock);
20591b4e487SEugen Hristev 	regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_CAPTURE);
20691b4e487SEugen Hristev 	spin_unlock(&isc->awb_lock);
20791b4e487SEugen Hristev }
20891b4e487SEugen Hristev 
20991b4e487SEugen Hristev static void isc_set_pipeline(struct isc_device *isc, u32 pipeline)
21091b4e487SEugen Hristev {
21191b4e487SEugen Hristev 	struct regmap *regmap = isc->regmap;
21291b4e487SEugen Hristev 	struct isc_ctrls *ctrls = &isc->ctrls;
21391b4e487SEugen Hristev 	u32 val, bay_cfg;
21491b4e487SEugen Hristev 	const u32 *gamma;
21591b4e487SEugen Hristev 	unsigned int i;
21691b4e487SEugen Hristev 
21791b4e487SEugen Hristev 	/* WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB422-->SUB420 */
21891b4e487SEugen Hristev 	for (i = 0; i < ISC_PIPE_LINE_NODE_NUM; i++) {
21991b4e487SEugen Hristev 		val = pipeline & BIT(i) ? 1 : 0;
22091b4e487SEugen Hristev 		regmap_field_write(isc->pipeline[i], val);
22191b4e487SEugen Hristev 	}
22291b4e487SEugen Hristev 
22391b4e487SEugen Hristev 	if (!pipeline)
22491b4e487SEugen Hristev 		return;
22591b4e487SEugen Hristev 
22691b4e487SEugen Hristev 	bay_cfg = isc->config.sd_format->cfa_baycfg;
22791b4e487SEugen Hristev 
22891b4e487SEugen Hristev 	regmap_write(regmap, ISC_WB_CFG, bay_cfg);
22991b4e487SEugen Hristev 	isc_update_awb_ctrls(isc);
23091b4e487SEugen Hristev 	isc_update_v4l2_ctrls(isc);
23191b4e487SEugen Hristev 
23291b4e487SEugen Hristev 	regmap_write(regmap, ISC_CFA_CFG, bay_cfg | ISC_CFA_CFG_EITPOL);
23391b4e487SEugen Hristev 
23491b4e487SEugen Hristev 	gamma = &isc->gamma_table[ctrls->gamma_index][0];
23591b4e487SEugen Hristev 	regmap_bulk_write(regmap, ISC_GAM_BENTRY, gamma, GAMMA_ENTRIES);
23691b4e487SEugen Hristev 	regmap_bulk_write(regmap, ISC_GAM_GENTRY, gamma, GAMMA_ENTRIES);
23791b4e487SEugen Hristev 	regmap_bulk_write(regmap, ISC_GAM_RENTRY, gamma, GAMMA_ENTRIES);
23891b4e487SEugen Hristev 
23991b4e487SEugen Hristev 	isc->config_dpc(isc);
24091b4e487SEugen Hristev 	isc->config_csc(isc);
24191b4e487SEugen Hristev 	isc->config_cbc(isc);
24291b4e487SEugen Hristev 	isc->config_cc(isc);
24391b4e487SEugen Hristev 	isc->config_gam(isc);
24491b4e487SEugen Hristev }
24591b4e487SEugen Hristev 
24691b4e487SEugen Hristev static int isc_update_profile(struct isc_device *isc)
24791b4e487SEugen Hristev {
24891b4e487SEugen Hristev 	struct regmap *regmap = isc->regmap;
24991b4e487SEugen Hristev 	u32 sr;
25091b4e487SEugen Hristev 	int counter = 100;
25191b4e487SEugen Hristev 
25291b4e487SEugen Hristev 	regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_UPPRO);
25391b4e487SEugen Hristev 
25491b4e487SEugen Hristev 	regmap_read(regmap, ISC_CTRLSR, &sr);
25591b4e487SEugen Hristev 	while ((sr & ISC_CTRL_UPPRO) && counter--) {
25691b4e487SEugen Hristev 		usleep_range(1000, 2000);
25791b4e487SEugen Hristev 		regmap_read(regmap, ISC_CTRLSR, &sr);
25891b4e487SEugen Hristev 	}
25991b4e487SEugen Hristev 
26091b4e487SEugen Hristev 	if (counter < 0) {
26191b4e487SEugen Hristev 		v4l2_warn(&isc->v4l2_dev, "Time out to update profile\n");
26291b4e487SEugen Hristev 		return -ETIMEDOUT;
26391b4e487SEugen Hristev 	}
26491b4e487SEugen Hristev 
26591b4e487SEugen Hristev 	return 0;
26691b4e487SEugen Hristev }
26791b4e487SEugen Hristev 
26891b4e487SEugen Hristev static void isc_set_histogram(struct isc_device *isc, bool enable)
26991b4e487SEugen Hristev {
27091b4e487SEugen Hristev 	struct regmap *regmap = isc->regmap;
27191b4e487SEugen Hristev 	struct isc_ctrls *ctrls = &isc->ctrls;
27291b4e487SEugen Hristev 
27391b4e487SEugen Hristev 	if (enable) {
27491b4e487SEugen Hristev 		regmap_write(regmap, ISC_HIS_CFG + isc->offsets.his,
27591b4e487SEugen Hristev 			     ISC_HIS_CFG_MODE_GR |
27691b4e487SEugen Hristev 			     (isc->config.sd_format->cfa_baycfg
27791b4e487SEugen Hristev 					<< ISC_HIS_CFG_BAYSEL_SHIFT) |
27891b4e487SEugen Hristev 					ISC_HIS_CFG_RAR);
27991b4e487SEugen Hristev 		regmap_write(regmap, ISC_HIS_CTRL + isc->offsets.his,
28091b4e487SEugen Hristev 			     ISC_HIS_CTRL_EN);
28191b4e487SEugen Hristev 		regmap_write(regmap, ISC_INTEN, ISC_INT_HISDONE);
28291b4e487SEugen Hristev 		ctrls->hist_id = ISC_HIS_CFG_MODE_GR;
28391b4e487SEugen Hristev 		isc_update_profile(isc);
28491b4e487SEugen Hristev 		regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ);
28591b4e487SEugen Hristev 
28691b4e487SEugen Hristev 		ctrls->hist_stat = HIST_ENABLED;
28791b4e487SEugen Hristev 	} else {
28891b4e487SEugen Hristev 		regmap_write(regmap, ISC_INTDIS, ISC_INT_HISDONE);
28991b4e487SEugen Hristev 		regmap_write(regmap, ISC_HIS_CTRL + isc->offsets.his,
29091b4e487SEugen Hristev 			     ISC_HIS_CTRL_DIS);
29191b4e487SEugen Hristev 
29291b4e487SEugen Hristev 		ctrls->hist_stat = HIST_DISABLED;
29391b4e487SEugen Hristev 	}
29491b4e487SEugen Hristev }
29591b4e487SEugen Hristev 
29691b4e487SEugen Hristev static int isc_configure(struct isc_device *isc)
29791b4e487SEugen Hristev {
29891b4e487SEugen Hristev 	struct regmap *regmap = isc->regmap;
29991b4e487SEugen Hristev 	u32 pfe_cfg0, dcfg, mask, pipeline;
30091b4e487SEugen Hristev 	struct isc_subdev_entity *subdev = isc->current_subdev;
30191b4e487SEugen Hristev 
30291b4e487SEugen Hristev 	pfe_cfg0 = isc->config.sd_format->pfe_cfg0_bps;
30391b4e487SEugen Hristev 	pipeline = isc->config.bits_pipeline;
30491b4e487SEugen Hristev 
30591b4e487SEugen Hristev 	dcfg = isc->config.dcfg_imode | isc->dcfg;
30691b4e487SEugen Hristev 
30791b4e487SEugen Hristev 	pfe_cfg0  |= subdev->pfe_cfg0 | ISC_PFE_CFG0_MODE_PROGRESSIVE;
30891b4e487SEugen Hristev 	mask = ISC_PFE_CFG0_BPS_MASK | ISC_PFE_CFG0_HPOL_LOW |
30991b4e487SEugen Hristev 	       ISC_PFE_CFG0_VPOL_LOW | ISC_PFE_CFG0_PPOL_LOW |
31091b4e487SEugen Hristev 	       ISC_PFE_CFG0_MODE_MASK | ISC_PFE_CFG0_CCIR_CRC |
31191b4e487SEugen Hristev 	       ISC_PFE_CFG0_CCIR656 | ISC_PFE_CFG0_MIPI;
31291b4e487SEugen Hristev 
31391b4e487SEugen Hristev 	regmap_update_bits(regmap, ISC_PFE_CFG0, mask, pfe_cfg0);
31491b4e487SEugen Hristev 
31591b4e487SEugen Hristev 	isc->config_rlp(isc);
31691b4e487SEugen Hristev 
31791b4e487SEugen Hristev 	regmap_write(regmap, ISC_DCFG + isc->offsets.dma, dcfg);
31891b4e487SEugen Hristev 
31991b4e487SEugen Hristev 	/* Set the pipeline */
32091b4e487SEugen Hristev 	isc_set_pipeline(isc, pipeline);
32191b4e487SEugen Hristev 
32291b4e487SEugen Hristev 	/*
32391b4e487SEugen Hristev 	 * The current implemented histogram is available for RAW R, B, GB, GR
32491b4e487SEugen Hristev 	 * channels. We need to check if sensor is outputting RAW BAYER
32591b4e487SEugen Hristev 	 */
32691b4e487SEugen Hristev 	if (isc->ctrls.awb &&
32791b4e487SEugen Hristev 	    ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code))
32891b4e487SEugen Hristev 		isc_set_histogram(isc, true);
32991b4e487SEugen Hristev 	else
33091b4e487SEugen Hristev 		isc_set_histogram(isc, false);
33191b4e487SEugen Hristev 
33291b4e487SEugen Hristev 	/* Update profile */
33391b4e487SEugen Hristev 	return isc_update_profile(isc);
33491b4e487SEugen Hristev }
33591b4e487SEugen Hristev 
33691b4e487SEugen Hristev static int isc_start_streaming(struct vb2_queue *vq, unsigned int count)
33791b4e487SEugen Hristev {
33891b4e487SEugen Hristev 	struct isc_device *isc = vb2_get_drv_priv(vq);
33991b4e487SEugen Hristev 	struct regmap *regmap = isc->regmap;
34091b4e487SEugen Hristev 	struct isc_buffer *buf;
34191b4e487SEugen Hristev 	unsigned long flags;
34291b4e487SEugen Hristev 	int ret;
34391b4e487SEugen Hristev 
34491b4e487SEugen Hristev 	/* Enable stream on the sub device */
34591b4e487SEugen Hristev 	ret = v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 1);
34691b4e487SEugen Hristev 	if (ret && ret != -ENOIOCTLCMD) {
34791b4e487SEugen Hristev 		v4l2_err(&isc->v4l2_dev, "stream on failed in subdev %d\n",
34891b4e487SEugen Hristev 			 ret);
34991b4e487SEugen Hristev 		goto err_start_stream;
35091b4e487SEugen Hristev 	}
35191b4e487SEugen Hristev 
35291b4e487SEugen Hristev 	ret = pm_runtime_resume_and_get(isc->dev);
35391b4e487SEugen Hristev 	if (ret < 0) {
35491b4e487SEugen Hristev 		v4l2_err(&isc->v4l2_dev, "RPM resume failed in subdev %d\n",
35591b4e487SEugen Hristev 			 ret);
35691b4e487SEugen Hristev 		goto err_pm_get;
35791b4e487SEugen Hristev 	}
35891b4e487SEugen Hristev 
35991b4e487SEugen Hristev 	ret = isc_configure(isc);
36091b4e487SEugen Hristev 	if (unlikely(ret))
36191b4e487SEugen Hristev 		goto err_configure;
36291b4e487SEugen Hristev 
36391b4e487SEugen Hristev 	/* Enable DMA interrupt */
36491b4e487SEugen Hristev 	regmap_write(regmap, ISC_INTEN, ISC_INT_DDONE);
36591b4e487SEugen Hristev 
36691b4e487SEugen Hristev 	spin_lock_irqsave(&isc->dma_queue_lock, flags);
36791b4e487SEugen Hristev 
36891b4e487SEugen Hristev 	isc->sequence = 0;
36991b4e487SEugen Hristev 	isc->stop = false;
37091b4e487SEugen Hristev 	reinit_completion(&isc->comp);
37191b4e487SEugen Hristev 
37291b4e487SEugen Hristev 	isc->cur_frm = list_first_entry(&isc->dma_queue,
37391b4e487SEugen Hristev 					struct isc_buffer, list);
37491b4e487SEugen Hristev 	list_del(&isc->cur_frm->list);
37591b4e487SEugen Hristev 
37691b4e487SEugen Hristev 	isc_crop_pfe(isc);
37791b4e487SEugen Hristev 	isc_start_dma(isc);
37891b4e487SEugen Hristev 
37991b4e487SEugen Hristev 	spin_unlock_irqrestore(&isc->dma_queue_lock, flags);
38091b4e487SEugen Hristev 
38191b4e487SEugen Hristev 	/* if we streaming from RAW, we can do one-shot white balance adj */
38291b4e487SEugen Hristev 	if (ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code))
38391b4e487SEugen Hristev 		v4l2_ctrl_activate(isc->do_wb_ctrl, true);
38491b4e487SEugen Hristev 
38591b4e487SEugen Hristev 	return 0;
38691b4e487SEugen Hristev 
38791b4e487SEugen Hristev err_configure:
38891b4e487SEugen Hristev 	pm_runtime_put_sync(isc->dev);
38991b4e487SEugen Hristev err_pm_get:
39091b4e487SEugen Hristev 	v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 0);
39191b4e487SEugen Hristev 
39291b4e487SEugen Hristev err_start_stream:
39391b4e487SEugen Hristev 	spin_lock_irqsave(&isc->dma_queue_lock, flags);
39491b4e487SEugen Hristev 	list_for_each_entry(buf, &isc->dma_queue, list)
39591b4e487SEugen Hristev 		vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED);
39691b4e487SEugen Hristev 	INIT_LIST_HEAD(&isc->dma_queue);
39791b4e487SEugen Hristev 	spin_unlock_irqrestore(&isc->dma_queue_lock, flags);
39891b4e487SEugen Hristev 
39991b4e487SEugen Hristev 	return ret;
40091b4e487SEugen Hristev }
40191b4e487SEugen Hristev 
40291b4e487SEugen Hristev static void isc_stop_streaming(struct vb2_queue *vq)
40391b4e487SEugen Hristev {
40491b4e487SEugen Hristev 	struct isc_device *isc = vb2_get_drv_priv(vq);
40591b4e487SEugen Hristev 	unsigned long flags;
40691b4e487SEugen Hristev 	struct isc_buffer *buf;
40791b4e487SEugen Hristev 	int ret;
40891b4e487SEugen Hristev 
40991b4e487SEugen Hristev 	mutex_lock(&isc->awb_mutex);
41091b4e487SEugen Hristev 	v4l2_ctrl_activate(isc->do_wb_ctrl, false);
41191b4e487SEugen Hristev 
41291b4e487SEugen Hristev 	isc->stop = true;
41391b4e487SEugen Hristev 
41491b4e487SEugen Hristev 	/* Wait until the end of the current frame */
41591b4e487SEugen Hristev 	if (isc->cur_frm && !wait_for_completion_timeout(&isc->comp, 5 * HZ))
41691b4e487SEugen Hristev 		v4l2_err(&isc->v4l2_dev,
41791b4e487SEugen Hristev 			 "Timeout waiting for end of the capture\n");
41891b4e487SEugen Hristev 
41991b4e487SEugen Hristev 	mutex_unlock(&isc->awb_mutex);
42091b4e487SEugen Hristev 
42191b4e487SEugen Hristev 	/* Disable DMA interrupt */
42291b4e487SEugen Hristev 	regmap_write(isc->regmap, ISC_INTDIS, ISC_INT_DDONE);
42391b4e487SEugen Hristev 
42491b4e487SEugen Hristev 	pm_runtime_put_sync(isc->dev);
42591b4e487SEugen Hristev 
42691b4e487SEugen Hristev 	/* Disable stream on the sub device */
42791b4e487SEugen Hristev 	ret = v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 0);
42891b4e487SEugen Hristev 	if (ret && ret != -ENOIOCTLCMD)
42991b4e487SEugen Hristev 		v4l2_err(&isc->v4l2_dev, "stream off failed in subdev\n");
43091b4e487SEugen Hristev 
43191b4e487SEugen Hristev 	/* Release all active buffers */
43291b4e487SEugen Hristev 	spin_lock_irqsave(&isc->dma_queue_lock, flags);
43391b4e487SEugen Hristev 	if (unlikely(isc->cur_frm)) {
43491b4e487SEugen Hristev 		vb2_buffer_done(&isc->cur_frm->vb.vb2_buf,
43591b4e487SEugen Hristev 				VB2_BUF_STATE_ERROR);
43691b4e487SEugen Hristev 		isc->cur_frm = NULL;
43791b4e487SEugen Hristev 	}
43891b4e487SEugen Hristev 	list_for_each_entry(buf, &isc->dma_queue, list)
43991b4e487SEugen Hristev 		vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
44091b4e487SEugen Hristev 	INIT_LIST_HEAD(&isc->dma_queue);
44191b4e487SEugen Hristev 	spin_unlock_irqrestore(&isc->dma_queue_lock, flags);
44291b4e487SEugen Hristev }
44391b4e487SEugen Hristev 
44491b4e487SEugen Hristev static void isc_buffer_queue(struct vb2_buffer *vb)
44591b4e487SEugen Hristev {
44691b4e487SEugen Hristev 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
44791b4e487SEugen Hristev 	struct isc_buffer *buf = container_of(vbuf, struct isc_buffer, vb);
44891b4e487SEugen Hristev 	struct isc_device *isc = vb2_get_drv_priv(vb->vb2_queue);
44991b4e487SEugen Hristev 	unsigned long flags;
45091b4e487SEugen Hristev 
45191b4e487SEugen Hristev 	spin_lock_irqsave(&isc->dma_queue_lock, flags);
45291b4e487SEugen Hristev 	if (!isc->cur_frm && list_empty(&isc->dma_queue) &&
45391b4e487SEugen Hristev 	    vb2_start_streaming_called(vb->vb2_queue)) {
45491b4e487SEugen Hristev 		isc->cur_frm = buf;
45591b4e487SEugen Hristev 		isc_start_dma(isc);
45691b4e487SEugen Hristev 	} else {
45791b4e487SEugen Hristev 		list_add_tail(&buf->list, &isc->dma_queue);
45891b4e487SEugen Hristev 	}
45991b4e487SEugen Hristev 	spin_unlock_irqrestore(&isc->dma_queue_lock, flags);
46091b4e487SEugen Hristev }
46191b4e487SEugen Hristev 
46291b4e487SEugen Hristev static struct isc_format *find_format_by_fourcc(struct isc_device *isc,
46391b4e487SEugen Hristev 						unsigned int fourcc)
46491b4e487SEugen Hristev {
46591b4e487SEugen Hristev 	unsigned int num_formats = isc->num_user_formats;
46691b4e487SEugen Hristev 	struct isc_format *fmt;
46791b4e487SEugen Hristev 	unsigned int i;
46891b4e487SEugen Hristev 
46991b4e487SEugen Hristev 	for (i = 0; i < num_formats; i++) {
47091b4e487SEugen Hristev 		fmt = isc->user_formats[i];
47191b4e487SEugen Hristev 		if (fmt->fourcc == fourcc)
47291b4e487SEugen Hristev 			return fmt;
47391b4e487SEugen Hristev 	}
47491b4e487SEugen Hristev 
47591b4e487SEugen Hristev 	return NULL;
47691b4e487SEugen Hristev }
47791b4e487SEugen Hristev 
47891b4e487SEugen Hristev static const struct vb2_ops isc_vb2_ops = {
47991b4e487SEugen Hristev 	.queue_setup		= isc_queue_setup,
48091b4e487SEugen Hristev 	.wait_prepare		= vb2_ops_wait_prepare,
48191b4e487SEugen Hristev 	.wait_finish		= vb2_ops_wait_finish,
48291b4e487SEugen Hristev 	.buf_prepare		= isc_buffer_prepare,
48391b4e487SEugen Hristev 	.start_streaming	= isc_start_streaming,
48491b4e487SEugen Hristev 	.stop_streaming		= isc_stop_streaming,
48591b4e487SEugen Hristev 	.buf_queue		= isc_buffer_queue,
48691b4e487SEugen Hristev };
48791b4e487SEugen Hristev 
48891b4e487SEugen Hristev static int isc_querycap(struct file *file, void *priv,
48991b4e487SEugen Hristev 			struct v4l2_capability *cap)
49091b4e487SEugen Hristev {
49191b4e487SEugen Hristev 	struct isc_device *isc = video_drvdata(file);
49291b4e487SEugen Hristev 
49391b4e487SEugen Hristev 	strscpy(cap->driver, "microchip-isc", sizeof(cap->driver));
49491b4e487SEugen Hristev 	strscpy(cap->card, "Microchip Image Sensor Controller", sizeof(cap->card));
49591b4e487SEugen Hristev 	snprintf(cap->bus_info, sizeof(cap->bus_info),
49691b4e487SEugen Hristev 		 "platform:%s", isc->v4l2_dev.name);
49791b4e487SEugen Hristev 
49891b4e487SEugen Hristev 	return 0;
49991b4e487SEugen Hristev }
50091b4e487SEugen Hristev 
50191b4e487SEugen Hristev static int isc_enum_fmt_vid_cap(struct file *file, void *priv,
50291b4e487SEugen Hristev 				struct v4l2_fmtdesc *f)
50391b4e487SEugen Hristev {
50491b4e487SEugen Hristev 	struct isc_device *isc = video_drvdata(file);
50591b4e487SEugen Hristev 	u32 index = f->index;
50691b4e487SEugen Hristev 	u32 i, supported_index;
50791b4e487SEugen Hristev 
50891b4e487SEugen Hristev 	if (index < isc->controller_formats_size) {
50991b4e487SEugen Hristev 		f->pixelformat = isc->controller_formats[index].fourcc;
51091b4e487SEugen Hristev 		return 0;
51191b4e487SEugen Hristev 	}
51291b4e487SEugen Hristev 
51391b4e487SEugen Hristev 	index -= isc->controller_formats_size;
51491b4e487SEugen Hristev 
51591b4e487SEugen Hristev 	supported_index = 0;
51691b4e487SEugen Hristev 
51791b4e487SEugen Hristev 	for (i = 0; i < isc->formats_list_size; i++) {
51891b4e487SEugen Hristev 		if (!ISC_IS_FORMAT_RAW(isc->formats_list[i].mbus_code) ||
51991b4e487SEugen Hristev 		    !isc->formats_list[i].sd_support)
52091b4e487SEugen Hristev 			continue;
52191b4e487SEugen Hristev 		if (supported_index == index) {
52291b4e487SEugen Hristev 			f->pixelformat = isc->formats_list[i].fourcc;
52391b4e487SEugen Hristev 			return 0;
52491b4e487SEugen Hristev 		}
52591b4e487SEugen Hristev 		supported_index++;
52691b4e487SEugen Hristev 	}
52791b4e487SEugen Hristev 
52891b4e487SEugen Hristev 	return -EINVAL;
52991b4e487SEugen Hristev }
53091b4e487SEugen Hristev 
53191b4e487SEugen Hristev static int isc_g_fmt_vid_cap(struct file *file, void *priv,
53291b4e487SEugen Hristev 			     struct v4l2_format *fmt)
53391b4e487SEugen Hristev {
53491b4e487SEugen Hristev 	struct isc_device *isc = video_drvdata(file);
53591b4e487SEugen Hristev 
53691b4e487SEugen Hristev 	*fmt = isc->fmt;
53791b4e487SEugen Hristev 
53891b4e487SEugen Hristev 	return 0;
53991b4e487SEugen Hristev }
54091b4e487SEugen Hristev 
54191b4e487SEugen Hristev /*
54291b4e487SEugen Hristev  * Checks the current configured format, if ISC can output it,
54391b4e487SEugen Hristev  * considering which type of format the ISC receives from the sensor
54491b4e487SEugen Hristev  */
54591b4e487SEugen Hristev static int isc_try_validate_formats(struct isc_device *isc)
54691b4e487SEugen Hristev {
54791b4e487SEugen Hristev 	int ret;
54891b4e487SEugen Hristev 	bool bayer = false, yuv = false, rgb = false, grey = false;
54991b4e487SEugen Hristev 
55091b4e487SEugen Hristev 	/* all formats supported by the RLP module are OK */
55191b4e487SEugen Hristev 	switch (isc->try_config.fourcc) {
55291b4e487SEugen Hristev 	case V4L2_PIX_FMT_SBGGR8:
55391b4e487SEugen Hristev 	case V4L2_PIX_FMT_SGBRG8:
55491b4e487SEugen Hristev 	case V4L2_PIX_FMT_SGRBG8:
55591b4e487SEugen Hristev 	case V4L2_PIX_FMT_SRGGB8:
55691b4e487SEugen Hristev 	case V4L2_PIX_FMT_SBGGR10:
55791b4e487SEugen Hristev 	case V4L2_PIX_FMT_SGBRG10:
55891b4e487SEugen Hristev 	case V4L2_PIX_FMT_SGRBG10:
55991b4e487SEugen Hristev 	case V4L2_PIX_FMT_SRGGB10:
56091b4e487SEugen Hristev 	case V4L2_PIX_FMT_SBGGR12:
56191b4e487SEugen Hristev 	case V4L2_PIX_FMT_SGBRG12:
56291b4e487SEugen Hristev 	case V4L2_PIX_FMT_SGRBG12:
56391b4e487SEugen Hristev 	case V4L2_PIX_FMT_SRGGB12:
56491b4e487SEugen Hristev 		ret = 0;
56591b4e487SEugen Hristev 		bayer = true;
56691b4e487SEugen Hristev 		break;
56791b4e487SEugen Hristev 
56891b4e487SEugen Hristev 	case V4L2_PIX_FMT_YUV420:
56991b4e487SEugen Hristev 	case V4L2_PIX_FMT_YUV422P:
57091b4e487SEugen Hristev 	case V4L2_PIX_FMT_YUYV:
57191b4e487SEugen Hristev 	case V4L2_PIX_FMT_UYVY:
57291b4e487SEugen Hristev 	case V4L2_PIX_FMT_VYUY:
57391b4e487SEugen Hristev 		ret = 0;
57491b4e487SEugen Hristev 		yuv = true;
57591b4e487SEugen Hristev 		break;
57691b4e487SEugen Hristev 
57791b4e487SEugen Hristev 	case V4L2_PIX_FMT_RGB565:
57891b4e487SEugen Hristev 	case V4L2_PIX_FMT_ABGR32:
57991b4e487SEugen Hristev 	case V4L2_PIX_FMT_XBGR32:
58091b4e487SEugen Hristev 	case V4L2_PIX_FMT_ARGB444:
58191b4e487SEugen Hristev 	case V4L2_PIX_FMT_ARGB555:
58291b4e487SEugen Hristev 		ret = 0;
58391b4e487SEugen Hristev 		rgb = true;
58491b4e487SEugen Hristev 		break;
58591b4e487SEugen Hristev 	case V4L2_PIX_FMT_GREY:
58691b4e487SEugen Hristev 	case V4L2_PIX_FMT_Y10:
58791b4e487SEugen Hristev 	case V4L2_PIX_FMT_Y16:
58891b4e487SEugen Hristev 		ret = 0;
58991b4e487SEugen Hristev 		grey = true;
59091b4e487SEugen Hristev 		break;
59191b4e487SEugen Hristev 	default:
59291b4e487SEugen Hristev 	/* any other different formats are not supported */
59391b4e487SEugen Hristev 		ret = -EINVAL;
59491b4e487SEugen Hristev 	}
59591b4e487SEugen Hristev 	v4l2_dbg(1, debug, &isc->v4l2_dev,
59691b4e487SEugen Hristev 		 "Format validation, requested rgb=%u, yuv=%u, grey=%u, bayer=%u\n",
59791b4e487SEugen Hristev 		 rgb, yuv, grey, bayer);
59891b4e487SEugen Hristev 
59991b4e487SEugen Hristev 	/* we cannot output RAW if we do not receive RAW */
60091b4e487SEugen Hristev 	if ((bayer) && !ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code))
60191b4e487SEugen Hristev 		return -EINVAL;
60291b4e487SEugen Hristev 
60391b4e487SEugen Hristev 	/* we cannot output GREY if we do not receive RAW/GREY */
60491b4e487SEugen Hristev 	if (grey && !ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code) &&
60591b4e487SEugen Hristev 	    !ISC_IS_FORMAT_GREY(isc->try_config.sd_format->mbus_code))
60691b4e487SEugen Hristev 		return -EINVAL;
60791b4e487SEugen Hristev 
60891b4e487SEugen Hristev 	return ret;
60991b4e487SEugen Hristev }
61091b4e487SEugen Hristev 
61191b4e487SEugen Hristev /*
61291b4e487SEugen Hristev  * Configures the RLP and DMA modules, depending on the output format
61391b4e487SEugen Hristev  * configured for the ISC.
61491b4e487SEugen Hristev  * If direct_dump == true, just dump raw data 8/16 bits depending on format.
61591b4e487SEugen Hristev  */
61691b4e487SEugen Hristev static int isc_try_configure_rlp_dma(struct isc_device *isc, bool direct_dump)
61791b4e487SEugen Hristev {
61891b4e487SEugen Hristev 	isc->try_config.rlp_cfg_mode = 0;
61991b4e487SEugen Hristev 
62091b4e487SEugen Hristev 	switch (isc->try_config.fourcc) {
62191b4e487SEugen Hristev 	case V4L2_PIX_FMT_SBGGR8:
62291b4e487SEugen Hristev 	case V4L2_PIX_FMT_SGBRG8:
62391b4e487SEugen Hristev 	case V4L2_PIX_FMT_SGRBG8:
62491b4e487SEugen Hristev 	case V4L2_PIX_FMT_SRGGB8:
62591b4e487SEugen Hristev 		isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8;
62691b4e487SEugen Hristev 		isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED8;
62791b4e487SEugen Hristev 		isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
62891b4e487SEugen Hristev 		isc->try_config.bpp = 8;
62991b4e487SEugen Hristev 		isc->try_config.bpp_v4l2 = 8;
63091b4e487SEugen Hristev 		break;
63191b4e487SEugen Hristev 	case V4L2_PIX_FMT_SBGGR10:
63291b4e487SEugen Hristev 	case V4L2_PIX_FMT_SGBRG10:
63391b4e487SEugen Hristev 	case V4L2_PIX_FMT_SGRBG10:
63491b4e487SEugen Hristev 	case V4L2_PIX_FMT_SRGGB10:
63591b4e487SEugen Hristev 		isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT10;
63691b4e487SEugen Hristev 		isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16;
63791b4e487SEugen Hristev 		isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
63891b4e487SEugen Hristev 		isc->try_config.bpp = 16;
63991b4e487SEugen Hristev 		isc->try_config.bpp_v4l2 = 16;
64091b4e487SEugen Hristev 		break;
64191b4e487SEugen Hristev 	case V4L2_PIX_FMT_SBGGR12:
64291b4e487SEugen Hristev 	case V4L2_PIX_FMT_SGBRG12:
64391b4e487SEugen Hristev 	case V4L2_PIX_FMT_SGRBG12:
64491b4e487SEugen Hristev 	case V4L2_PIX_FMT_SRGGB12:
64591b4e487SEugen Hristev 		isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT12;
64691b4e487SEugen Hristev 		isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16;
64791b4e487SEugen Hristev 		isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
64891b4e487SEugen Hristev 		isc->try_config.bpp = 16;
64991b4e487SEugen Hristev 		isc->try_config.bpp_v4l2 = 16;
65091b4e487SEugen Hristev 		break;
65191b4e487SEugen Hristev 	case V4L2_PIX_FMT_RGB565:
65291b4e487SEugen Hristev 		isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_RGB565;
65391b4e487SEugen Hristev 		isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16;
65491b4e487SEugen Hristev 		isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
65591b4e487SEugen Hristev 		isc->try_config.bpp = 16;
65691b4e487SEugen Hristev 		isc->try_config.bpp_v4l2 = 16;
65791b4e487SEugen Hristev 		break;
65891b4e487SEugen Hristev 	case V4L2_PIX_FMT_ARGB444:
65991b4e487SEugen Hristev 		isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB444;
66091b4e487SEugen Hristev 		isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16;
66191b4e487SEugen Hristev 		isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
66291b4e487SEugen Hristev 		isc->try_config.bpp = 16;
66391b4e487SEugen Hristev 		isc->try_config.bpp_v4l2 = 16;
66491b4e487SEugen Hristev 		break;
66591b4e487SEugen Hristev 	case V4L2_PIX_FMT_ARGB555:
66691b4e487SEugen Hristev 		isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB555;
66791b4e487SEugen Hristev 		isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16;
66891b4e487SEugen Hristev 		isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
66991b4e487SEugen Hristev 		isc->try_config.bpp = 16;
67091b4e487SEugen Hristev 		isc->try_config.bpp_v4l2 = 16;
67191b4e487SEugen Hristev 		break;
67291b4e487SEugen Hristev 	case V4L2_PIX_FMT_ABGR32:
67391b4e487SEugen Hristev 	case V4L2_PIX_FMT_XBGR32:
67491b4e487SEugen Hristev 		isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB32;
67591b4e487SEugen Hristev 		isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED32;
67691b4e487SEugen Hristev 		isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
67791b4e487SEugen Hristev 		isc->try_config.bpp = 32;
67891b4e487SEugen Hristev 		isc->try_config.bpp_v4l2 = 32;
67991b4e487SEugen Hristev 		break;
68091b4e487SEugen Hristev 	case V4L2_PIX_FMT_YUV420:
68191b4e487SEugen Hristev 		isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC;
68291b4e487SEugen Hristev 		isc->try_config.dcfg_imode = ISC_DCFG_IMODE_YC420P;
68391b4e487SEugen Hristev 		isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PLANAR;
68491b4e487SEugen Hristev 		isc->try_config.bpp = 12;
68591b4e487SEugen Hristev 		isc->try_config.bpp_v4l2 = 8; /* only first plane */
68691b4e487SEugen Hristev 		break;
68791b4e487SEugen Hristev 	case V4L2_PIX_FMT_YUV422P:
68891b4e487SEugen Hristev 		isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC;
68991b4e487SEugen Hristev 		isc->try_config.dcfg_imode = ISC_DCFG_IMODE_YC422P;
69091b4e487SEugen Hristev 		isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PLANAR;
69191b4e487SEugen Hristev 		isc->try_config.bpp = 16;
69291b4e487SEugen Hristev 		isc->try_config.bpp_v4l2 = 8; /* only first plane */
69391b4e487SEugen Hristev 		break;
69491b4e487SEugen Hristev 	case V4L2_PIX_FMT_YUYV:
69591b4e487SEugen Hristev 		isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YCYC | ISC_RLP_CFG_YMODE_YUYV;
69691b4e487SEugen Hristev 		isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED32;
69791b4e487SEugen Hristev 		isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
69891b4e487SEugen Hristev 		isc->try_config.bpp = 16;
69991b4e487SEugen Hristev 		isc->try_config.bpp_v4l2 = 16;
70091b4e487SEugen Hristev 		break;
70191b4e487SEugen Hristev 	case V4L2_PIX_FMT_UYVY:
70291b4e487SEugen Hristev 		isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YCYC | ISC_RLP_CFG_YMODE_UYVY;
70391b4e487SEugen Hristev 		isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED32;
70491b4e487SEugen Hristev 		isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
70591b4e487SEugen Hristev 		isc->try_config.bpp = 16;
70691b4e487SEugen Hristev 		isc->try_config.bpp_v4l2 = 16;
70791b4e487SEugen Hristev 		break;
70891b4e487SEugen Hristev 	case V4L2_PIX_FMT_VYUY:
70991b4e487SEugen Hristev 		isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YCYC | ISC_RLP_CFG_YMODE_VYUY;
71091b4e487SEugen Hristev 		isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED32;
71191b4e487SEugen Hristev 		isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
71291b4e487SEugen Hristev 		isc->try_config.bpp = 16;
71391b4e487SEugen Hristev 		isc->try_config.bpp_v4l2 = 16;
71491b4e487SEugen Hristev 		break;
71591b4e487SEugen Hristev 	case V4L2_PIX_FMT_GREY:
71691b4e487SEugen Hristev 		isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DATY8;
71791b4e487SEugen Hristev 		isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED8;
71891b4e487SEugen Hristev 		isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
71991b4e487SEugen Hristev 		isc->try_config.bpp = 8;
72091b4e487SEugen Hristev 		isc->try_config.bpp_v4l2 = 8;
72191b4e487SEugen Hristev 		break;
72291b4e487SEugen Hristev 	case V4L2_PIX_FMT_Y16:
72391b4e487SEugen Hristev 		isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DATY10 | ISC_RLP_CFG_LSH;
72491b4e487SEugen Hristev 		fallthrough;
72591b4e487SEugen Hristev 	case V4L2_PIX_FMT_Y10:
72691b4e487SEugen Hristev 		isc->try_config.rlp_cfg_mode |= ISC_RLP_CFG_MODE_DATY10;
72791b4e487SEugen Hristev 		isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16;
72891b4e487SEugen Hristev 		isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
72991b4e487SEugen Hristev 		isc->try_config.bpp = 16;
73091b4e487SEugen Hristev 		isc->try_config.bpp_v4l2 = 16;
73191b4e487SEugen Hristev 		break;
73291b4e487SEugen Hristev 	default:
73391b4e487SEugen Hristev 		return -EINVAL;
73491b4e487SEugen Hristev 	}
73591b4e487SEugen Hristev 
73691b4e487SEugen Hristev 	if (direct_dump) {
73791b4e487SEugen Hristev 		isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8;
73891b4e487SEugen Hristev 		isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED8;
73991b4e487SEugen Hristev 		isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
74091b4e487SEugen Hristev 		return 0;
74191b4e487SEugen Hristev 	}
74291b4e487SEugen Hristev 
74391b4e487SEugen Hristev 	return 0;
74491b4e487SEugen Hristev }
74591b4e487SEugen Hristev 
74691b4e487SEugen Hristev /*
74791b4e487SEugen Hristev  * Configuring pipeline modules, depending on which format the ISC outputs
74891b4e487SEugen Hristev  * and considering which format it has as input from the sensor.
74991b4e487SEugen Hristev  */
75091b4e487SEugen Hristev static int isc_try_configure_pipeline(struct isc_device *isc)
75191b4e487SEugen Hristev {
75291b4e487SEugen Hristev 	switch (isc->try_config.fourcc) {
75391b4e487SEugen Hristev 	case V4L2_PIX_FMT_RGB565:
75491b4e487SEugen Hristev 	case V4L2_PIX_FMT_ARGB555:
75591b4e487SEugen Hristev 	case V4L2_PIX_FMT_ARGB444:
75691b4e487SEugen Hristev 	case V4L2_PIX_FMT_ABGR32:
75791b4e487SEugen Hristev 	case V4L2_PIX_FMT_XBGR32:
75891b4e487SEugen Hristev 		/* if sensor format is RAW, we convert inside ISC */
75991b4e487SEugen Hristev 		if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
76091b4e487SEugen Hristev 			isc->try_config.bits_pipeline = CFA_ENABLE |
76191b4e487SEugen Hristev 				WB_ENABLE | GAM_ENABLES | DPC_BLCENABLE |
76291b4e487SEugen Hristev 				CC_ENABLE;
76391b4e487SEugen Hristev 		} else {
76491b4e487SEugen Hristev 			isc->try_config.bits_pipeline = 0x0;
76591b4e487SEugen Hristev 		}
76691b4e487SEugen Hristev 		break;
76791b4e487SEugen Hristev 	case V4L2_PIX_FMT_YUV420:
76891b4e487SEugen Hristev 		/* if sensor format is RAW, we convert inside ISC */
76991b4e487SEugen Hristev 		if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
77091b4e487SEugen Hristev 			isc->try_config.bits_pipeline = CFA_ENABLE |
77191b4e487SEugen Hristev 				CSC_ENABLE | GAM_ENABLES | WB_ENABLE |
77291b4e487SEugen Hristev 				SUB420_ENABLE | SUB422_ENABLE | CBC_ENABLE |
77391b4e487SEugen Hristev 				DPC_BLCENABLE;
77491b4e487SEugen Hristev 		} else {
77591b4e487SEugen Hristev 			isc->try_config.bits_pipeline = 0x0;
77691b4e487SEugen Hristev 		}
77791b4e487SEugen Hristev 		break;
77891b4e487SEugen Hristev 	case V4L2_PIX_FMT_YUV422P:
77991b4e487SEugen Hristev 		/* if sensor format is RAW, we convert inside ISC */
78091b4e487SEugen Hristev 		if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
78191b4e487SEugen Hristev 			isc->try_config.bits_pipeline = CFA_ENABLE |
78291b4e487SEugen Hristev 				CSC_ENABLE | WB_ENABLE | GAM_ENABLES |
78391b4e487SEugen Hristev 				SUB422_ENABLE | CBC_ENABLE | DPC_BLCENABLE;
78491b4e487SEugen Hristev 		} else {
78591b4e487SEugen Hristev 			isc->try_config.bits_pipeline = 0x0;
78691b4e487SEugen Hristev 		}
78791b4e487SEugen Hristev 		break;
78891b4e487SEugen Hristev 	case V4L2_PIX_FMT_YUYV:
78991b4e487SEugen Hristev 	case V4L2_PIX_FMT_UYVY:
79091b4e487SEugen Hristev 	case V4L2_PIX_FMT_VYUY:
79191b4e487SEugen Hristev 		/* if sensor format is RAW, we convert inside ISC */
79291b4e487SEugen Hristev 		if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
79391b4e487SEugen Hristev 			isc->try_config.bits_pipeline = CFA_ENABLE |
79491b4e487SEugen Hristev 				CSC_ENABLE | WB_ENABLE | GAM_ENABLES |
79591b4e487SEugen Hristev 				SUB422_ENABLE | CBC_ENABLE | DPC_BLCENABLE;
79691b4e487SEugen Hristev 		} else {
79791b4e487SEugen Hristev 			isc->try_config.bits_pipeline = 0x0;
79891b4e487SEugen Hristev 		}
79991b4e487SEugen Hristev 		break;
80091b4e487SEugen Hristev 	case V4L2_PIX_FMT_GREY:
80191b4e487SEugen Hristev 	case V4L2_PIX_FMT_Y16:
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 | WB_ENABLE | GAM_ENABLES |
80691b4e487SEugen Hristev 				CBC_ENABLE | DPC_BLCENABLE;
80791b4e487SEugen Hristev 		} else {
80891b4e487SEugen Hristev 			isc->try_config.bits_pipeline = 0x0;
80991b4e487SEugen Hristev 		}
81091b4e487SEugen Hristev 		break;
81191b4e487SEugen Hristev 	default:
81291b4e487SEugen Hristev 		if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code))
81391b4e487SEugen Hristev 			isc->try_config.bits_pipeline = WB_ENABLE | DPC_BLCENABLE;
81491b4e487SEugen Hristev 		else
81591b4e487SEugen Hristev 			isc->try_config.bits_pipeline = 0x0;
81691b4e487SEugen Hristev 	}
81791b4e487SEugen Hristev 
81891b4e487SEugen Hristev 	/* Tune the pipeline to product specific */
81991b4e487SEugen Hristev 	isc->adapt_pipeline(isc);
82091b4e487SEugen Hristev 
82191b4e487SEugen Hristev 	return 0;
82291b4e487SEugen Hristev }
82391b4e487SEugen Hristev 
82491b4e487SEugen Hristev static void isc_try_fse(struct isc_device *isc,
82591b4e487SEugen Hristev 			struct v4l2_subdev_state *sd_state)
82691b4e487SEugen Hristev {
82791b4e487SEugen Hristev 	int ret;
82891b4e487SEugen Hristev 	struct v4l2_subdev_frame_size_enum fse = {};
82991b4e487SEugen Hristev 
83091b4e487SEugen Hristev 	/*
83191b4e487SEugen Hristev 	 * If we do not know yet which format the subdev is using, we cannot
83291b4e487SEugen Hristev 	 * do anything.
83391b4e487SEugen Hristev 	 */
83491b4e487SEugen Hristev 	if (!isc->try_config.sd_format)
83591b4e487SEugen Hristev 		return;
83691b4e487SEugen Hristev 
83791b4e487SEugen Hristev 	fse.code = isc->try_config.sd_format->mbus_code;
83891b4e487SEugen Hristev 	fse.which = V4L2_SUBDEV_FORMAT_TRY;
83991b4e487SEugen Hristev 
84091b4e487SEugen Hristev 	ret = v4l2_subdev_call(isc->current_subdev->sd, pad, enum_frame_size,
84191b4e487SEugen Hristev 			       sd_state, &fse);
84291b4e487SEugen Hristev 	/*
84391b4e487SEugen Hristev 	 * Attempt to obtain format size from subdev. If not available,
84491b4e487SEugen Hristev 	 * just use the maximum ISC can receive.
84591b4e487SEugen Hristev 	 */
84691b4e487SEugen Hristev 	if (ret) {
84791b4e487SEugen Hristev 		sd_state->pads->try_crop.width = isc->max_width;
84891b4e487SEugen Hristev 		sd_state->pads->try_crop.height = isc->max_height;
84991b4e487SEugen Hristev 	} else {
85091b4e487SEugen Hristev 		sd_state->pads->try_crop.width = fse.max_width;
85191b4e487SEugen Hristev 		sd_state->pads->try_crop.height = fse.max_height;
85291b4e487SEugen Hristev 	}
85391b4e487SEugen Hristev }
85491b4e487SEugen Hristev 
85591b4e487SEugen Hristev static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f,
85691b4e487SEugen Hristev 		       u32 *code)
85791b4e487SEugen Hristev {
85891b4e487SEugen Hristev 	int i;
85991b4e487SEugen Hristev 	struct isc_format *sd_fmt = NULL, *direct_fmt = NULL;
86091b4e487SEugen Hristev 	struct v4l2_pix_format *pixfmt = &f->fmt.pix;
86191b4e487SEugen Hristev 	struct v4l2_subdev_pad_config pad_cfg = {};
86291b4e487SEugen Hristev 	struct v4l2_subdev_state pad_state = {
86391b4e487SEugen Hristev 		.pads = &pad_cfg
86491b4e487SEugen Hristev 		};
86591b4e487SEugen Hristev 	struct v4l2_subdev_format format = {
86691b4e487SEugen Hristev 		.which = V4L2_SUBDEV_FORMAT_TRY,
86791b4e487SEugen Hristev 	};
86891b4e487SEugen Hristev 	u32 mbus_code;
86991b4e487SEugen Hristev 	int ret;
87091b4e487SEugen Hristev 	bool rlp_dma_direct_dump = false;
87191b4e487SEugen Hristev 
87291b4e487SEugen Hristev 	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
87391b4e487SEugen Hristev 		return -EINVAL;
87491b4e487SEugen Hristev 
87591b4e487SEugen Hristev 	/* Step 1: find a RAW format that is supported */
87691b4e487SEugen Hristev 	for (i = 0; i < isc->num_user_formats; i++) {
87791b4e487SEugen Hristev 		if (ISC_IS_FORMAT_RAW(isc->user_formats[i]->mbus_code)) {
87891b4e487SEugen Hristev 			sd_fmt = isc->user_formats[i];
87991b4e487SEugen Hristev 			break;
88091b4e487SEugen Hristev 		}
88191b4e487SEugen Hristev 	}
88291b4e487SEugen Hristev 	/* Step 2: We can continue with this RAW format, or we can look
88391b4e487SEugen Hristev 	 * for better: maybe sensor supports directly what we need.
88491b4e487SEugen Hristev 	 */
88591b4e487SEugen Hristev 	direct_fmt = find_format_by_fourcc(isc, pixfmt->pixelformat);
88691b4e487SEugen Hristev 
88791b4e487SEugen Hristev 	/* Step 3: We have both. We decide given the module parameter which
88891b4e487SEugen Hristev 	 * one to use.
88991b4e487SEugen Hristev 	 */
89091b4e487SEugen Hristev 	if (direct_fmt && sd_fmt && sensor_preferred)
89191b4e487SEugen Hristev 		sd_fmt = direct_fmt;
89291b4e487SEugen Hristev 
89391b4e487SEugen Hristev 	/* Step 4: we do not have RAW but we have a direct format. Use it. */
89491b4e487SEugen Hristev 	if (direct_fmt && !sd_fmt)
89591b4e487SEugen Hristev 		sd_fmt = direct_fmt;
89691b4e487SEugen Hristev 
89791b4e487SEugen Hristev 	/* Step 5: if we are using a direct format, we need to package
89891b4e487SEugen Hristev 	 * everything as 8 bit data and just dump it
89991b4e487SEugen Hristev 	 */
90091b4e487SEugen Hristev 	if (sd_fmt == direct_fmt)
90191b4e487SEugen Hristev 		rlp_dma_direct_dump = true;
90291b4e487SEugen Hristev 
90391b4e487SEugen Hristev 	/* Step 6: We have no format. This can happen if the userspace
90491b4e487SEugen Hristev 	 * requests some weird/invalid format.
90591b4e487SEugen Hristev 	 * In this case, default to whatever we have
90691b4e487SEugen Hristev 	 */
90791b4e487SEugen Hristev 	if (!sd_fmt && !direct_fmt) {
90891b4e487SEugen Hristev 		sd_fmt = isc->user_formats[isc->num_user_formats - 1];
90991b4e487SEugen Hristev 		v4l2_dbg(1, debug, &isc->v4l2_dev,
91091b4e487SEugen Hristev 			 "Sensor not supporting %.4s, using %.4s\n",
91191b4e487SEugen Hristev 			 (char *)&pixfmt->pixelformat, (char *)&sd_fmt->fourcc);
91291b4e487SEugen Hristev 	}
91391b4e487SEugen Hristev 
91491b4e487SEugen Hristev 	if (!sd_fmt) {
91591b4e487SEugen Hristev 		ret = -EINVAL;
91691b4e487SEugen Hristev 		goto isc_try_fmt_err;
91791b4e487SEugen Hristev 	}
91891b4e487SEugen Hristev 
91991b4e487SEugen Hristev 	/* Step 7: Print out what we decided for debugging */
92091b4e487SEugen Hristev 	v4l2_dbg(1, debug, &isc->v4l2_dev,
92191b4e487SEugen Hristev 		 "Preferring to have sensor using format %.4s\n",
92291b4e487SEugen Hristev 		 (char *)&sd_fmt->fourcc);
92391b4e487SEugen Hristev 
92491b4e487SEugen Hristev 	/* Step 8: at this moment we decided which format the subdev will use */
92591b4e487SEugen Hristev 	isc->try_config.sd_format = sd_fmt;
92691b4e487SEugen Hristev 
92791b4e487SEugen Hristev 	/* Limit to Microchip ISC hardware capabilities */
92891b4e487SEugen Hristev 	if (pixfmt->width > isc->max_width)
92991b4e487SEugen Hristev 		pixfmt->width = isc->max_width;
93091b4e487SEugen Hristev 	if (pixfmt->height > isc->max_height)
93191b4e487SEugen Hristev 		pixfmt->height = isc->max_height;
93291b4e487SEugen Hristev 
93391b4e487SEugen Hristev 	/*
93491b4e487SEugen Hristev 	 * The mbus format is the one the subdev outputs.
93591b4e487SEugen Hristev 	 * The pixels will be transferred in this format Sensor -> ISC
93691b4e487SEugen Hristev 	 */
93791b4e487SEugen Hristev 	mbus_code = sd_fmt->mbus_code;
93891b4e487SEugen Hristev 
93991b4e487SEugen Hristev 	/*
94091b4e487SEugen Hristev 	 * Validate formats. If the required format is not OK, default to raw.
94191b4e487SEugen Hristev 	 */
94291b4e487SEugen Hristev 
94391b4e487SEugen Hristev 	isc->try_config.fourcc = pixfmt->pixelformat;
94491b4e487SEugen Hristev 
94591b4e487SEugen Hristev 	if (isc_try_validate_formats(isc)) {
94691b4e487SEugen Hristev 		pixfmt->pixelformat = isc->try_config.fourcc = sd_fmt->fourcc;
94791b4e487SEugen Hristev 		/* Re-try to validate the new format */
94891b4e487SEugen Hristev 		ret = isc_try_validate_formats(isc);
94991b4e487SEugen Hristev 		if (ret)
95091b4e487SEugen Hristev 			goto isc_try_fmt_err;
95191b4e487SEugen Hristev 	}
95291b4e487SEugen Hristev 
95391b4e487SEugen Hristev 	ret = isc_try_configure_rlp_dma(isc, rlp_dma_direct_dump);
95491b4e487SEugen Hristev 	if (ret)
95591b4e487SEugen Hristev 		goto isc_try_fmt_err;
95691b4e487SEugen Hristev 
95791b4e487SEugen Hristev 	ret = isc_try_configure_pipeline(isc);
95891b4e487SEugen Hristev 	if (ret)
95991b4e487SEugen Hristev 		goto isc_try_fmt_err;
96091b4e487SEugen Hristev 
96191b4e487SEugen Hristev 	/* Obtain frame sizes if possible to have crop requirements ready */
96291b4e487SEugen Hristev 	isc_try_fse(isc, &pad_state);
96391b4e487SEugen Hristev 
96491b4e487SEugen Hristev 	v4l2_fill_mbus_format(&format.format, pixfmt, mbus_code);
96591b4e487SEugen Hristev 	ret = v4l2_subdev_call(isc->current_subdev->sd, pad, set_fmt,
96691b4e487SEugen Hristev 			       &pad_state, &format);
96791b4e487SEugen Hristev 	if (ret < 0)
96891b4e487SEugen Hristev 		goto isc_try_fmt_subdev_err;
96991b4e487SEugen Hristev 
97091b4e487SEugen Hristev 	v4l2_fill_pix_format(pixfmt, &format.format);
97191b4e487SEugen Hristev 
97291b4e487SEugen Hristev 	/* Limit to Microchip ISC hardware capabilities */
97391b4e487SEugen Hristev 	if (pixfmt->width > isc->max_width)
97491b4e487SEugen Hristev 		pixfmt->width = isc->max_width;
97591b4e487SEugen Hristev 	if (pixfmt->height > isc->max_height)
97691b4e487SEugen Hristev 		pixfmt->height = isc->max_height;
97791b4e487SEugen Hristev 
97891b4e487SEugen Hristev 	pixfmt->field = V4L2_FIELD_NONE;
97991b4e487SEugen Hristev 	pixfmt->bytesperline = (pixfmt->width * isc->try_config.bpp_v4l2) >> 3;
98091b4e487SEugen Hristev 	pixfmt->sizeimage = ((pixfmt->width * isc->try_config.bpp) >> 3) *
98191b4e487SEugen Hristev 			     pixfmt->height;
98291b4e487SEugen Hristev 
98391b4e487SEugen Hristev 	if (code)
98491b4e487SEugen Hristev 		*code = mbus_code;
98591b4e487SEugen Hristev 
98691b4e487SEugen Hristev 	return 0;
98791b4e487SEugen Hristev 
98891b4e487SEugen Hristev isc_try_fmt_err:
98991b4e487SEugen Hristev 	v4l2_err(&isc->v4l2_dev, "Could not find any possible format for a working pipeline\n");
99091b4e487SEugen Hristev isc_try_fmt_subdev_err:
99191b4e487SEugen Hristev 	memset(&isc->try_config, 0, sizeof(isc->try_config));
99291b4e487SEugen Hristev 
99391b4e487SEugen Hristev 	return ret;
99491b4e487SEugen Hristev }
99591b4e487SEugen Hristev 
99691b4e487SEugen Hristev static int isc_set_fmt(struct isc_device *isc, struct v4l2_format *f)
99791b4e487SEugen Hristev {
99891b4e487SEugen Hristev 	struct v4l2_subdev_format format = {
99991b4e487SEugen Hristev 		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
100091b4e487SEugen Hristev 	};
100191b4e487SEugen Hristev 	u32 mbus_code = 0;
100291b4e487SEugen Hristev 	int ret;
100391b4e487SEugen Hristev 
100491b4e487SEugen Hristev 	ret = isc_try_fmt(isc, f, &mbus_code);
100591b4e487SEugen Hristev 	if (ret)
100691b4e487SEugen Hristev 		return ret;
100791b4e487SEugen Hristev 
100891b4e487SEugen Hristev 	v4l2_fill_mbus_format(&format.format, &f->fmt.pix, mbus_code);
100991b4e487SEugen Hristev 	ret = v4l2_subdev_call(isc->current_subdev->sd, pad,
101091b4e487SEugen Hristev 			       set_fmt, NULL, &format);
101191b4e487SEugen Hristev 	if (ret < 0)
101291b4e487SEugen Hristev 		return ret;
101391b4e487SEugen Hristev 
101491b4e487SEugen Hristev 	/* Limit to Microchip ISC hardware capabilities */
101591b4e487SEugen Hristev 	if (f->fmt.pix.width > isc->max_width)
101691b4e487SEugen Hristev 		f->fmt.pix.width = isc->max_width;
101791b4e487SEugen Hristev 	if (f->fmt.pix.height > isc->max_height)
101891b4e487SEugen Hristev 		f->fmt.pix.height = isc->max_height;
101991b4e487SEugen Hristev 
102091b4e487SEugen Hristev 	isc->fmt = *f;
102191b4e487SEugen Hristev 
102291b4e487SEugen Hristev 	if (isc->try_config.sd_format && isc->config.sd_format &&
102391b4e487SEugen Hristev 	    isc->try_config.sd_format != isc->config.sd_format) {
102491b4e487SEugen Hristev 		isc->ctrls.hist_stat = HIST_INIT;
102591b4e487SEugen Hristev 		isc_reset_awb_ctrls(isc);
102691b4e487SEugen Hristev 		isc_update_v4l2_ctrls(isc);
102791b4e487SEugen Hristev 	}
102891b4e487SEugen Hristev 	/* make the try configuration active */
102991b4e487SEugen Hristev 	isc->config = isc->try_config;
103091b4e487SEugen Hristev 
103191b4e487SEugen Hristev 	v4l2_dbg(1, debug, &isc->v4l2_dev, "New ISC configuration in place\n");
103291b4e487SEugen Hristev 
103391b4e487SEugen Hristev 	return 0;
103491b4e487SEugen Hristev }
103591b4e487SEugen Hristev 
103691b4e487SEugen Hristev static int isc_s_fmt_vid_cap(struct file *file, void *priv,
103791b4e487SEugen Hristev 			     struct v4l2_format *f)
103891b4e487SEugen Hristev {
103991b4e487SEugen Hristev 	struct isc_device *isc = video_drvdata(file);
104091b4e487SEugen Hristev 
104191b4e487SEugen Hristev 	if (vb2_is_busy(&isc->vb2_vidq))
104291b4e487SEugen Hristev 		return -EBUSY;
104391b4e487SEugen Hristev 
104491b4e487SEugen Hristev 	return isc_set_fmt(isc, f);
104591b4e487SEugen Hristev }
104691b4e487SEugen Hristev 
104791b4e487SEugen Hristev static int isc_try_fmt_vid_cap(struct file *file, void *priv,
104891b4e487SEugen Hristev 			       struct v4l2_format *f)
104991b4e487SEugen Hristev {
105091b4e487SEugen Hristev 	struct isc_device *isc = video_drvdata(file);
105191b4e487SEugen Hristev 
105291b4e487SEugen Hristev 	return isc_try_fmt(isc, f, NULL);
105391b4e487SEugen Hristev }
105491b4e487SEugen Hristev 
105591b4e487SEugen Hristev static int isc_enum_input(struct file *file, void *priv,
105691b4e487SEugen Hristev 			  struct v4l2_input *inp)
105791b4e487SEugen Hristev {
105891b4e487SEugen Hristev 	if (inp->index != 0)
105991b4e487SEugen Hristev 		return -EINVAL;
106091b4e487SEugen Hristev 
106191b4e487SEugen Hristev 	inp->type = V4L2_INPUT_TYPE_CAMERA;
106291b4e487SEugen Hristev 	inp->std = 0;
106391b4e487SEugen Hristev 	strscpy(inp->name, "Camera", sizeof(inp->name));
106491b4e487SEugen Hristev 
106591b4e487SEugen Hristev 	return 0;
106691b4e487SEugen Hristev }
106791b4e487SEugen Hristev 
106891b4e487SEugen Hristev static int isc_g_input(struct file *file, void *priv, unsigned int *i)
106991b4e487SEugen Hristev {
107091b4e487SEugen Hristev 	*i = 0;
107191b4e487SEugen Hristev 
107291b4e487SEugen Hristev 	return 0;
107391b4e487SEugen Hristev }
107491b4e487SEugen Hristev 
107591b4e487SEugen Hristev static int isc_s_input(struct file *file, void *priv, unsigned int i)
107691b4e487SEugen Hristev {
107791b4e487SEugen Hristev 	if (i > 0)
107891b4e487SEugen Hristev 		return -EINVAL;
107991b4e487SEugen Hristev 
108091b4e487SEugen Hristev 	return 0;
108191b4e487SEugen Hristev }
108291b4e487SEugen Hristev 
108391b4e487SEugen Hristev static int isc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
108491b4e487SEugen Hristev {
108591b4e487SEugen Hristev 	struct isc_device *isc = video_drvdata(file);
108691b4e487SEugen Hristev 
108791b4e487SEugen Hristev 	return v4l2_g_parm_cap(video_devdata(file), isc->current_subdev->sd, a);
108891b4e487SEugen Hristev }
108991b4e487SEugen Hristev 
109091b4e487SEugen Hristev static int isc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
109191b4e487SEugen Hristev {
109291b4e487SEugen Hristev 	struct isc_device *isc = video_drvdata(file);
109391b4e487SEugen Hristev 
109491b4e487SEugen Hristev 	return v4l2_s_parm_cap(video_devdata(file), isc->current_subdev->sd, a);
109591b4e487SEugen Hristev }
109691b4e487SEugen Hristev 
109791b4e487SEugen Hristev static int isc_enum_framesizes(struct file *file, void *fh,
109891b4e487SEugen Hristev 			       struct v4l2_frmsizeenum *fsize)
109991b4e487SEugen Hristev {
110091b4e487SEugen Hristev 	struct isc_device *isc = video_drvdata(file);
110191b4e487SEugen Hristev 	int ret = -EINVAL;
110291b4e487SEugen Hristev 	int i;
110391b4e487SEugen Hristev 
110491b4e487SEugen Hristev 	if (fsize->index)
110591b4e487SEugen Hristev 		return -EINVAL;
110691b4e487SEugen Hristev 
110791b4e487SEugen Hristev 	for (i = 0; i < isc->num_user_formats; i++)
110891b4e487SEugen Hristev 		if (isc->user_formats[i]->fourcc == fsize->pixel_format)
110991b4e487SEugen Hristev 			ret = 0;
111091b4e487SEugen Hristev 
111191b4e487SEugen Hristev 	for (i = 0; i < isc->controller_formats_size; i++)
111291b4e487SEugen Hristev 		if (isc->controller_formats[i].fourcc == fsize->pixel_format)
111391b4e487SEugen Hristev 			ret = 0;
111491b4e487SEugen Hristev 
111591b4e487SEugen Hristev 	if (ret)
111691b4e487SEugen Hristev 		return ret;
111791b4e487SEugen Hristev 
111891b4e487SEugen Hristev 	fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
111991b4e487SEugen Hristev 
112091b4e487SEugen Hristev 	fsize->stepwise.min_width = 16;
112191b4e487SEugen Hristev 	fsize->stepwise.max_width = isc->max_width;
112291b4e487SEugen Hristev 	fsize->stepwise.min_height = 16;
112391b4e487SEugen Hristev 	fsize->stepwise.max_height = isc->max_height;
112491b4e487SEugen Hristev 	fsize->stepwise.step_width = 1;
112591b4e487SEugen Hristev 	fsize->stepwise.step_height = 1;
112691b4e487SEugen Hristev 
112791b4e487SEugen Hristev 	return 0;
112891b4e487SEugen Hristev }
112991b4e487SEugen Hristev 
113091b4e487SEugen Hristev static const struct v4l2_ioctl_ops isc_ioctl_ops = {
113191b4e487SEugen Hristev 	.vidioc_querycap		= isc_querycap,
113291b4e487SEugen Hristev 	.vidioc_enum_fmt_vid_cap	= isc_enum_fmt_vid_cap,
113391b4e487SEugen Hristev 	.vidioc_g_fmt_vid_cap		= isc_g_fmt_vid_cap,
113491b4e487SEugen Hristev 	.vidioc_s_fmt_vid_cap		= isc_s_fmt_vid_cap,
113591b4e487SEugen Hristev 	.vidioc_try_fmt_vid_cap		= isc_try_fmt_vid_cap,
113691b4e487SEugen Hristev 
113791b4e487SEugen Hristev 	.vidioc_enum_input		= isc_enum_input,
113891b4e487SEugen Hristev 	.vidioc_g_input			= isc_g_input,
113991b4e487SEugen Hristev 	.vidioc_s_input			= isc_s_input,
114091b4e487SEugen Hristev 
114191b4e487SEugen Hristev 	.vidioc_reqbufs			= vb2_ioctl_reqbufs,
114291b4e487SEugen Hristev 	.vidioc_querybuf		= vb2_ioctl_querybuf,
114391b4e487SEugen Hristev 	.vidioc_qbuf			= vb2_ioctl_qbuf,
114491b4e487SEugen Hristev 	.vidioc_expbuf			= vb2_ioctl_expbuf,
114591b4e487SEugen Hristev 	.vidioc_dqbuf			= vb2_ioctl_dqbuf,
114691b4e487SEugen Hristev 	.vidioc_create_bufs		= vb2_ioctl_create_bufs,
114791b4e487SEugen Hristev 	.vidioc_prepare_buf		= vb2_ioctl_prepare_buf,
114891b4e487SEugen Hristev 	.vidioc_streamon		= vb2_ioctl_streamon,
114991b4e487SEugen Hristev 	.vidioc_streamoff		= vb2_ioctl_streamoff,
115091b4e487SEugen Hristev 
115191b4e487SEugen Hristev 	.vidioc_g_parm			= isc_g_parm,
115291b4e487SEugen Hristev 	.vidioc_s_parm			= isc_s_parm,
115391b4e487SEugen Hristev 	.vidioc_enum_framesizes		= isc_enum_framesizes,
115491b4e487SEugen Hristev 
115591b4e487SEugen Hristev 	.vidioc_log_status		= v4l2_ctrl_log_status,
115691b4e487SEugen Hristev 	.vidioc_subscribe_event		= v4l2_ctrl_subscribe_event,
115791b4e487SEugen Hristev 	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
115891b4e487SEugen Hristev };
115991b4e487SEugen Hristev 
116091b4e487SEugen Hristev static int isc_open(struct file *file)
116191b4e487SEugen Hristev {
116291b4e487SEugen Hristev 	struct isc_device *isc = video_drvdata(file);
116391b4e487SEugen Hristev 	struct v4l2_subdev *sd = isc->current_subdev->sd;
116491b4e487SEugen Hristev 	int ret;
116591b4e487SEugen Hristev 
116691b4e487SEugen Hristev 	if (mutex_lock_interruptible(&isc->lock))
116791b4e487SEugen Hristev 		return -ERESTARTSYS;
116891b4e487SEugen Hristev 
116991b4e487SEugen Hristev 	ret = v4l2_fh_open(file);
117091b4e487SEugen Hristev 	if (ret < 0)
117191b4e487SEugen Hristev 		goto unlock;
117291b4e487SEugen Hristev 
117391b4e487SEugen Hristev 	if (!v4l2_fh_is_singular_file(file))
117491b4e487SEugen Hristev 		goto unlock;
117591b4e487SEugen Hristev 
117691b4e487SEugen Hristev 	ret = v4l2_subdev_call(sd, core, s_power, 1);
117791b4e487SEugen Hristev 	if (ret < 0 && ret != -ENOIOCTLCMD) {
117891b4e487SEugen Hristev 		v4l2_fh_release(file);
117991b4e487SEugen Hristev 		goto unlock;
118091b4e487SEugen Hristev 	}
118191b4e487SEugen Hristev 
118291b4e487SEugen Hristev 	ret = isc_set_fmt(isc, &isc->fmt);
118391b4e487SEugen Hristev 	if (ret) {
118491b4e487SEugen Hristev 		v4l2_subdev_call(sd, core, s_power, 0);
118591b4e487SEugen Hristev 		v4l2_fh_release(file);
118691b4e487SEugen Hristev 	}
118791b4e487SEugen Hristev 
118891b4e487SEugen Hristev unlock:
118991b4e487SEugen Hristev 	mutex_unlock(&isc->lock);
119091b4e487SEugen Hristev 	return ret;
119191b4e487SEugen Hristev }
119291b4e487SEugen Hristev 
119391b4e487SEugen Hristev static int isc_release(struct file *file)
119491b4e487SEugen Hristev {
119591b4e487SEugen Hristev 	struct isc_device *isc = video_drvdata(file);
119691b4e487SEugen Hristev 	struct v4l2_subdev *sd = isc->current_subdev->sd;
119791b4e487SEugen Hristev 	bool fh_singular;
119891b4e487SEugen Hristev 	int ret;
119991b4e487SEugen Hristev 
120091b4e487SEugen Hristev 	mutex_lock(&isc->lock);
120191b4e487SEugen Hristev 
120291b4e487SEugen Hristev 	fh_singular = v4l2_fh_is_singular_file(file);
120391b4e487SEugen Hristev 
120491b4e487SEugen Hristev 	ret = _vb2_fop_release(file, NULL);
120591b4e487SEugen Hristev 
120691b4e487SEugen Hristev 	if (fh_singular)
120791b4e487SEugen Hristev 		v4l2_subdev_call(sd, core, s_power, 0);
120891b4e487SEugen Hristev 
120991b4e487SEugen Hristev 	mutex_unlock(&isc->lock);
121091b4e487SEugen Hristev 
121191b4e487SEugen Hristev 	return ret;
121291b4e487SEugen Hristev }
121391b4e487SEugen Hristev 
121491b4e487SEugen Hristev static const struct v4l2_file_operations isc_fops = {
121591b4e487SEugen Hristev 	.owner		= THIS_MODULE,
121691b4e487SEugen Hristev 	.open		= isc_open,
121791b4e487SEugen Hristev 	.release	= isc_release,
121891b4e487SEugen Hristev 	.unlocked_ioctl	= video_ioctl2,
121991b4e487SEugen Hristev 	.read		= vb2_fop_read,
122091b4e487SEugen Hristev 	.mmap		= vb2_fop_mmap,
122191b4e487SEugen Hristev 	.poll		= vb2_fop_poll,
122291b4e487SEugen Hristev };
122391b4e487SEugen Hristev 
122491b4e487SEugen Hristev irqreturn_t microchip_isc_interrupt(int irq, void *dev_id)
122591b4e487SEugen Hristev {
122691b4e487SEugen Hristev 	struct isc_device *isc = (struct isc_device *)dev_id;
122791b4e487SEugen Hristev 	struct regmap *regmap = isc->regmap;
122891b4e487SEugen Hristev 	u32 isc_intsr, isc_intmask, pending;
122991b4e487SEugen Hristev 	irqreturn_t ret = IRQ_NONE;
123091b4e487SEugen Hristev 
123191b4e487SEugen Hristev 	regmap_read(regmap, ISC_INTSR, &isc_intsr);
123291b4e487SEugen Hristev 	regmap_read(regmap, ISC_INTMASK, &isc_intmask);
123391b4e487SEugen Hristev 
123491b4e487SEugen Hristev 	pending = isc_intsr & isc_intmask;
123591b4e487SEugen Hristev 
123691b4e487SEugen Hristev 	if (likely(pending & ISC_INT_DDONE)) {
123791b4e487SEugen Hristev 		spin_lock(&isc->dma_queue_lock);
123891b4e487SEugen Hristev 		if (isc->cur_frm) {
123991b4e487SEugen Hristev 			struct vb2_v4l2_buffer *vbuf = &isc->cur_frm->vb;
124091b4e487SEugen Hristev 			struct vb2_buffer *vb = &vbuf->vb2_buf;
124191b4e487SEugen Hristev 
124291b4e487SEugen Hristev 			vb->timestamp = ktime_get_ns();
124391b4e487SEugen Hristev 			vbuf->sequence = isc->sequence++;
124491b4e487SEugen Hristev 			vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
124591b4e487SEugen Hristev 			isc->cur_frm = NULL;
124691b4e487SEugen Hristev 		}
124791b4e487SEugen Hristev 
124891b4e487SEugen Hristev 		if (!list_empty(&isc->dma_queue) && !isc->stop) {
124991b4e487SEugen Hristev 			isc->cur_frm = list_first_entry(&isc->dma_queue,
125091b4e487SEugen Hristev 							struct isc_buffer, list);
125191b4e487SEugen Hristev 			list_del(&isc->cur_frm->list);
125291b4e487SEugen Hristev 
125391b4e487SEugen Hristev 			isc_start_dma(isc);
125491b4e487SEugen Hristev 		}
125591b4e487SEugen Hristev 
125691b4e487SEugen Hristev 		if (isc->stop)
125791b4e487SEugen Hristev 			complete(&isc->comp);
125891b4e487SEugen Hristev 
125991b4e487SEugen Hristev 		ret = IRQ_HANDLED;
126091b4e487SEugen Hristev 		spin_unlock(&isc->dma_queue_lock);
126191b4e487SEugen Hristev 	}
126291b4e487SEugen Hristev 
126391b4e487SEugen Hristev 	if (pending & ISC_INT_HISDONE) {
126491b4e487SEugen Hristev 		schedule_work(&isc->awb_work);
126591b4e487SEugen Hristev 		ret = IRQ_HANDLED;
126691b4e487SEugen Hristev 	}
126791b4e487SEugen Hristev 
126891b4e487SEugen Hristev 	return ret;
126991b4e487SEugen Hristev }
127091b4e487SEugen Hristev EXPORT_SYMBOL_GPL(microchip_isc_interrupt);
127191b4e487SEugen Hristev 
127291b4e487SEugen Hristev static void isc_hist_count(struct isc_device *isc, u32 *min, u32 *max)
127391b4e487SEugen Hristev {
127491b4e487SEugen Hristev 	struct regmap *regmap = isc->regmap;
127591b4e487SEugen Hristev 	struct isc_ctrls *ctrls = &isc->ctrls;
127691b4e487SEugen Hristev 	u32 *hist_count = &ctrls->hist_count[ctrls->hist_id];
127791b4e487SEugen Hristev 	u32 *hist_entry = &ctrls->hist_entry[0];
127891b4e487SEugen Hristev 	u32 i;
127991b4e487SEugen Hristev 
128091b4e487SEugen Hristev 	*min = 0;
128191b4e487SEugen Hristev 	*max = HIST_ENTRIES;
128291b4e487SEugen Hristev 
128391b4e487SEugen Hristev 	regmap_bulk_read(regmap, ISC_HIS_ENTRY + isc->offsets.his_entry,
128491b4e487SEugen Hristev 			 hist_entry, HIST_ENTRIES);
128591b4e487SEugen Hristev 
128691b4e487SEugen Hristev 	*hist_count = 0;
128791b4e487SEugen Hristev 	/*
128891b4e487SEugen Hristev 	 * we deliberately ignore the end of the histogram,
128991b4e487SEugen Hristev 	 * the most white pixels
129091b4e487SEugen Hristev 	 */
129191b4e487SEugen Hristev 	for (i = 1; i < HIST_ENTRIES; i++) {
129291b4e487SEugen Hristev 		if (*hist_entry && !*min)
129391b4e487SEugen Hristev 			*min = i;
129491b4e487SEugen Hristev 		if (*hist_entry)
129591b4e487SEugen Hristev 			*max = i;
129691b4e487SEugen Hristev 		*hist_count += i * (*hist_entry++);
129791b4e487SEugen Hristev 	}
129891b4e487SEugen Hristev 
129991b4e487SEugen Hristev 	if (!*min)
130091b4e487SEugen Hristev 		*min = 1;
130191b4e487SEugen Hristev 
130291b4e487SEugen Hristev 	v4l2_dbg(1, debug, &isc->v4l2_dev,
130391b4e487SEugen Hristev 		 "isc wb: hist_id %u, hist_count %u",
130491b4e487SEugen Hristev 		 ctrls->hist_id, *hist_count);
130591b4e487SEugen Hristev }
130691b4e487SEugen Hristev 
130791b4e487SEugen Hristev static void isc_wb_update(struct isc_ctrls *ctrls)
130891b4e487SEugen Hristev {
130991b4e487SEugen Hristev 	struct isc_device *isc = container_of(ctrls, struct isc_device, ctrls);
131091b4e487SEugen Hristev 	u32 *hist_count = &ctrls->hist_count[0];
131191b4e487SEugen Hristev 	u32 c, offset[4];
131291b4e487SEugen Hristev 	u64 avg = 0;
131391b4e487SEugen Hristev 	/* We compute two gains, stretch gain and grey world gain */
131491b4e487SEugen Hristev 	u32 s_gain[4], gw_gain[4];
131591b4e487SEugen Hristev 
131691b4e487SEugen Hristev 	/*
131791b4e487SEugen Hristev 	 * According to Grey World, we need to set gains for R/B to normalize
131891b4e487SEugen Hristev 	 * them towards the green channel.
131991b4e487SEugen Hristev 	 * Thus we want to keep Green as fixed and adjust only Red/Blue
132091b4e487SEugen Hristev 	 * Compute the average of the both green channels first
132191b4e487SEugen Hristev 	 */
132291b4e487SEugen Hristev 	avg = (u64)hist_count[ISC_HIS_CFG_MODE_GR] +
132391b4e487SEugen Hristev 		(u64)hist_count[ISC_HIS_CFG_MODE_GB];
132491b4e487SEugen Hristev 	avg >>= 1;
132591b4e487SEugen Hristev 
132691b4e487SEugen Hristev 	v4l2_dbg(1, debug, &isc->v4l2_dev,
132791b4e487SEugen Hristev 		 "isc wb: green components average %llu\n", avg);
132891b4e487SEugen Hristev 
132991b4e487SEugen Hristev 	/* Green histogram is null, nothing to do */
133091b4e487SEugen Hristev 	if (!avg)
133191b4e487SEugen Hristev 		return;
133291b4e487SEugen Hristev 
133391b4e487SEugen Hristev 	for (c = ISC_HIS_CFG_MODE_GR; c <= ISC_HIS_CFG_MODE_B; c++) {
133491b4e487SEugen Hristev 		/*
133591b4e487SEugen Hristev 		 * the color offset is the minimum value of the histogram.
133691b4e487SEugen Hristev 		 * we stretch this color to the full range by substracting
133791b4e487SEugen Hristev 		 * this value from the color component.
133891b4e487SEugen Hristev 		 */
133991b4e487SEugen Hristev 		offset[c] = ctrls->hist_minmax[c][HIST_MIN_INDEX];
134091b4e487SEugen Hristev 		/*
134191b4e487SEugen Hristev 		 * The offset is always at least 1. If the offset is 1, we do
134291b4e487SEugen Hristev 		 * not need to adjust it, so our result must be zero.
134391b4e487SEugen Hristev 		 * the offset is computed in a histogram on 9 bits (0..512)
134491b4e487SEugen Hristev 		 * but the offset in register is based on
134591b4e487SEugen Hristev 		 * 12 bits pipeline (0..4096).
134691b4e487SEugen Hristev 		 * we need to shift with the 3 bits that the histogram is
134791b4e487SEugen Hristev 		 * ignoring
134891b4e487SEugen Hristev 		 */
134991b4e487SEugen Hristev 		ctrls->offset[c] = (offset[c] - 1) << 3;
135091b4e487SEugen Hristev 
135191b4e487SEugen Hristev 		/*
135291b4e487SEugen Hristev 		 * the offset is then taken and converted to 2's complements,
135391b4e487SEugen Hristev 		 * and must be negative, as we subtract this value from the
135491b4e487SEugen Hristev 		 * color components
135591b4e487SEugen Hristev 		 */
135691b4e487SEugen Hristev 		ctrls->offset[c] = -ctrls->offset[c];
135791b4e487SEugen Hristev 
135891b4e487SEugen Hristev 		/*
135991b4e487SEugen Hristev 		 * the stretch gain is the total number of histogram bins
136091b4e487SEugen Hristev 		 * divided by the actual range of color component (Max - Min)
136191b4e487SEugen Hristev 		 * If we compute gain like this, the actual color component
136291b4e487SEugen Hristev 		 * will be stretched to the full histogram.
136391b4e487SEugen Hristev 		 * We need to shift 9 bits for precision, we have 9 bits for
136491b4e487SEugen Hristev 		 * decimals
136591b4e487SEugen Hristev 		 */
136691b4e487SEugen Hristev 		s_gain[c] = (HIST_ENTRIES << 9) /
136791b4e487SEugen Hristev 			(ctrls->hist_minmax[c][HIST_MAX_INDEX] -
136891b4e487SEugen Hristev 			ctrls->hist_minmax[c][HIST_MIN_INDEX] + 1);
136991b4e487SEugen Hristev 
137091b4e487SEugen Hristev 		/*
137191b4e487SEugen Hristev 		 * Now we have to compute the gain w.r.t. the average.
137291b4e487SEugen Hristev 		 * Add/lose gain to the component towards the average.
137391b4e487SEugen Hristev 		 * If it happens that the component is zero, use the
137491b4e487SEugen Hristev 		 * fixed point value : 1.0 gain.
137591b4e487SEugen Hristev 		 */
137691b4e487SEugen Hristev 		if (hist_count[c])
137791b4e487SEugen Hristev 			gw_gain[c] = div_u64(avg << 9, hist_count[c]);
137891b4e487SEugen Hristev 		else
137991b4e487SEugen Hristev 			gw_gain[c] = 1 << 9;
138091b4e487SEugen Hristev 
138191b4e487SEugen Hristev 		v4l2_dbg(1, debug, &isc->v4l2_dev,
138291b4e487SEugen Hristev 			 "isc wb: component %d, s_gain %u, gw_gain %u\n",
138391b4e487SEugen Hristev 			 c, s_gain[c], gw_gain[c]);
138491b4e487SEugen Hristev 		/* multiply both gains and adjust for decimals */
138591b4e487SEugen Hristev 		ctrls->gain[c] = s_gain[c] * gw_gain[c];
138691b4e487SEugen Hristev 		ctrls->gain[c] >>= 9;
138791b4e487SEugen Hristev 
138891b4e487SEugen Hristev 		/* make sure we are not out of range */
138991b4e487SEugen Hristev 		ctrls->gain[c] = clamp_val(ctrls->gain[c], 0, GENMASK(12, 0));
139091b4e487SEugen Hristev 
139191b4e487SEugen Hristev 		v4l2_dbg(1, debug, &isc->v4l2_dev,
139291b4e487SEugen Hristev 			 "isc wb: component %d, final gain %u\n",
139391b4e487SEugen Hristev 			 c, ctrls->gain[c]);
139491b4e487SEugen Hristev 	}
139591b4e487SEugen Hristev }
139691b4e487SEugen Hristev 
139791b4e487SEugen Hristev static void isc_awb_work(struct work_struct *w)
139891b4e487SEugen Hristev {
139991b4e487SEugen Hristev 	struct isc_device *isc =
140091b4e487SEugen Hristev 		container_of(w, struct isc_device, awb_work);
140191b4e487SEugen Hristev 	struct regmap *regmap = isc->regmap;
140291b4e487SEugen Hristev 	struct isc_ctrls *ctrls = &isc->ctrls;
140391b4e487SEugen Hristev 	u32 hist_id = ctrls->hist_id;
140491b4e487SEugen Hristev 	u32 baysel;
140591b4e487SEugen Hristev 	unsigned long flags;
140691b4e487SEugen Hristev 	u32 min, max;
140791b4e487SEugen Hristev 	int ret;
140891b4e487SEugen Hristev 
140991b4e487SEugen Hristev 	if (ctrls->hist_stat != HIST_ENABLED)
141091b4e487SEugen Hristev 		return;
141191b4e487SEugen Hristev 
141291b4e487SEugen Hristev 	isc_hist_count(isc, &min, &max);
141391b4e487SEugen Hristev 
141491b4e487SEugen Hristev 	v4l2_dbg(1, debug, &isc->v4l2_dev,
141591b4e487SEugen Hristev 		 "isc wb mode %d: hist min %u , max %u\n", hist_id, min, max);
141691b4e487SEugen Hristev 
141791b4e487SEugen Hristev 	ctrls->hist_minmax[hist_id][HIST_MIN_INDEX] = min;
141891b4e487SEugen Hristev 	ctrls->hist_minmax[hist_id][HIST_MAX_INDEX] = max;
141991b4e487SEugen Hristev 
142091b4e487SEugen Hristev 	if (hist_id != ISC_HIS_CFG_MODE_B) {
142191b4e487SEugen Hristev 		hist_id++;
142291b4e487SEugen Hristev 	} else {
142391b4e487SEugen Hristev 		isc_wb_update(ctrls);
142491b4e487SEugen Hristev 		hist_id = ISC_HIS_CFG_MODE_GR;
142591b4e487SEugen Hristev 	}
142691b4e487SEugen Hristev 
142791b4e487SEugen Hristev 	ctrls->hist_id = hist_id;
142891b4e487SEugen Hristev 	baysel = isc->config.sd_format->cfa_baycfg << ISC_HIS_CFG_BAYSEL_SHIFT;
142991b4e487SEugen Hristev 
143091b4e487SEugen Hristev 	ret = pm_runtime_resume_and_get(isc->dev);
143191b4e487SEugen Hristev 	if (ret < 0)
143291b4e487SEugen Hristev 		return;
143391b4e487SEugen Hristev 
143491b4e487SEugen Hristev 	/*
143591b4e487SEugen Hristev 	 * only update if we have all the required histograms and controls
143691b4e487SEugen Hristev 	 * if awb has been disabled, we need to reset registers as well.
143791b4e487SEugen Hristev 	 */
143891b4e487SEugen Hristev 	if (hist_id == ISC_HIS_CFG_MODE_GR || ctrls->awb == ISC_WB_NONE) {
143991b4e487SEugen Hristev 		/*
144091b4e487SEugen Hristev 		 * It may happen that DMA Done IRQ will trigger while we are
144191b4e487SEugen Hristev 		 * updating white balance registers here.
144291b4e487SEugen Hristev 		 * In that case, only parts of the controls have been updated.
144391b4e487SEugen Hristev 		 * We can avoid that by locking the section.
144491b4e487SEugen Hristev 		 */
144591b4e487SEugen Hristev 		spin_lock_irqsave(&isc->awb_lock, flags);
144691b4e487SEugen Hristev 		isc_update_awb_ctrls(isc);
144791b4e487SEugen Hristev 		spin_unlock_irqrestore(&isc->awb_lock, flags);
144891b4e487SEugen Hristev 
144991b4e487SEugen Hristev 		/*
145091b4e487SEugen Hristev 		 * if we are doing just the one time white balance adjustment,
145191b4e487SEugen Hristev 		 * we are basically done.
145291b4e487SEugen Hristev 		 */
145391b4e487SEugen Hristev 		if (ctrls->awb == ISC_WB_ONETIME) {
145491b4e487SEugen Hristev 			v4l2_info(&isc->v4l2_dev,
145591b4e487SEugen Hristev 				  "Completed one time white-balance adjustment.\n");
145691b4e487SEugen Hristev 			/* update the v4l2 controls values */
145791b4e487SEugen Hristev 			isc_update_v4l2_ctrls(isc);
145891b4e487SEugen Hristev 			ctrls->awb = ISC_WB_NONE;
145991b4e487SEugen Hristev 		}
146091b4e487SEugen Hristev 	}
146191b4e487SEugen Hristev 	regmap_write(regmap, ISC_HIS_CFG + isc->offsets.his,
146291b4e487SEugen Hristev 		     hist_id | baysel | ISC_HIS_CFG_RAR);
146391b4e487SEugen Hristev 
146491b4e487SEugen Hristev 	/*
146591b4e487SEugen Hristev 	 * We have to make sure the streaming has not stopped meanwhile.
146691b4e487SEugen Hristev 	 * ISC requires a frame to clock the internal profile update.
146791b4e487SEugen Hristev 	 * To avoid issues, lock the sequence with a mutex
146891b4e487SEugen Hristev 	 */
146991b4e487SEugen Hristev 	mutex_lock(&isc->awb_mutex);
147091b4e487SEugen Hristev 
147191b4e487SEugen Hristev 	/* streaming is not active anymore */
147291b4e487SEugen Hristev 	if (isc->stop) {
147391b4e487SEugen Hristev 		mutex_unlock(&isc->awb_mutex);
147491b4e487SEugen Hristev 		return;
147591b4e487SEugen Hristev 	}
147691b4e487SEugen Hristev 
147791b4e487SEugen Hristev 	isc_update_profile(isc);
147891b4e487SEugen Hristev 
147991b4e487SEugen Hristev 	mutex_unlock(&isc->awb_mutex);
148091b4e487SEugen Hristev 
148191b4e487SEugen Hristev 	/* if awb has been disabled, we don't need to start another histogram */
148291b4e487SEugen Hristev 	if (ctrls->awb)
148391b4e487SEugen Hristev 		regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ);
148491b4e487SEugen Hristev 
148591b4e487SEugen Hristev 	pm_runtime_put_sync(isc->dev);
148691b4e487SEugen Hristev }
148791b4e487SEugen Hristev 
148891b4e487SEugen Hristev static int isc_s_ctrl(struct v4l2_ctrl *ctrl)
148991b4e487SEugen Hristev {
149091b4e487SEugen Hristev 	struct isc_device *isc = container_of(ctrl->handler,
149191b4e487SEugen Hristev 					     struct isc_device, ctrls.handler);
149291b4e487SEugen Hristev 	struct isc_ctrls *ctrls = &isc->ctrls;
149391b4e487SEugen Hristev 
149491b4e487SEugen Hristev 	if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
149591b4e487SEugen Hristev 		return 0;
149691b4e487SEugen Hristev 
149791b4e487SEugen Hristev 	switch (ctrl->id) {
149891b4e487SEugen Hristev 	case V4L2_CID_BRIGHTNESS:
149991b4e487SEugen Hristev 		ctrls->brightness = ctrl->val & ISC_CBC_BRIGHT_MASK;
150091b4e487SEugen Hristev 		break;
150191b4e487SEugen Hristev 	case V4L2_CID_CONTRAST:
150291b4e487SEugen Hristev 		ctrls->contrast = ctrl->val & ISC_CBC_CONTRAST_MASK;
150391b4e487SEugen Hristev 		break;
150491b4e487SEugen Hristev 	case V4L2_CID_GAMMA:
150591b4e487SEugen Hristev 		ctrls->gamma_index = ctrl->val;
150691b4e487SEugen Hristev 		break;
150791b4e487SEugen Hristev 	default:
150891b4e487SEugen Hristev 		return -EINVAL;
150991b4e487SEugen Hristev 	}
151091b4e487SEugen Hristev 
151191b4e487SEugen Hristev 	return 0;
151291b4e487SEugen Hristev }
151391b4e487SEugen Hristev 
151491b4e487SEugen Hristev static const struct v4l2_ctrl_ops isc_ctrl_ops = {
151591b4e487SEugen Hristev 	.s_ctrl	= isc_s_ctrl,
151691b4e487SEugen Hristev };
151791b4e487SEugen Hristev 
151891b4e487SEugen Hristev static int isc_s_awb_ctrl(struct v4l2_ctrl *ctrl)
151991b4e487SEugen Hristev {
152091b4e487SEugen Hristev 	struct isc_device *isc = container_of(ctrl->handler,
152191b4e487SEugen Hristev 					     struct isc_device, ctrls.handler);
152291b4e487SEugen Hristev 	struct isc_ctrls *ctrls = &isc->ctrls;
152391b4e487SEugen Hristev 
152491b4e487SEugen Hristev 	if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
152591b4e487SEugen Hristev 		return 0;
152691b4e487SEugen Hristev 
152791b4e487SEugen Hristev 	switch (ctrl->id) {
152891b4e487SEugen Hristev 	case V4L2_CID_AUTO_WHITE_BALANCE:
152991b4e487SEugen Hristev 		if (ctrl->val == 1)
153091b4e487SEugen Hristev 			ctrls->awb = ISC_WB_AUTO;
153191b4e487SEugen Hristev 		else
153291b4e487SEugen Hristev 			ctrls->awb = ISC_WB_NONE;
153391b4e487SEugen Hristev 
153491b4e487SEugen Hristev 		/* configure the controls with new values from v4l2 */
153591b4e487SEugen Hristev 		if (ctrl->cluster[ISC_CTRL_R_GAIN]->is_new)
153691b4e487SEugen Hristev 			ctrls->gain[ISC_HIS_CFG_MODE_R] = isc->r_gain_ctrl->val;
153791b4e487SEugen Hristev 		if (ctrl->cluster[ISC_CTRL_B_GAIN]->is_new)
153891b4e487SEugen Hristev 			ctrls->gain[ISC_HIS_CFG_MODE_B] = isc->b_gain_ctrl->val;
153991b4e487SEugen Hristev 		if (ctrl->cluster[ISC_CTRL_GR_GAIN]->is_new)
154091b4e487SEugen Hristev 			ctrls->gain[ISC_HIS_CFG_MODE_GR] = isc->gr_gain_ctrl->val;
154191b4e487SEugen Hristev 		if (ctrl->cluster[ISC_CTRL_GB_GAIN]->is_new)
154291b4e487SEugen Hristev 			ctrls->gain[ISC_HIS_CFG_MODE_GB] = isc->gb_gain_ctrl->val;
154391b4e487SEugen Hristev 
154491b4e487SEugen Hristev 		if (ctrl->cluster[ISC_CTRL_R_OFF]->is_new)
154591b4e487SEugen Hristev 			ctrls->offset[ISC_HIS_CFG_MODE_R] = isc->r_off_ctrl->val;
154691b4e487SEugen Hristev 		if (ctrl->cluster[ISC_CTRL_B_OFF]->is_new)
154791b4e487SEugen Hristev 			ctrls->offset[ISC_HIS_CFG_MODE_B] = isc->b_off_ctrl->val;
154891b4e487SEugen Hristev 		if (ctrl->cluster[ISC_CTRL_GR_OFF]->is_new)
154991b4e487SEugen Hristev 			ctrls->offset[ISC_HIS_CFG_MODE_GR] = isc->gr_off_ctrl->val;
155091b4e487SEugen Hristev 		if (ctrl->cluster[ISC_CTRL_GB_OFF]->is_new)
155191b4e487SEugen Hristev 			ctrls->offset[ISC_HIS_CFG_MODE_GB] = isc->gb_off_ctrl->val;
155291b4e487SEugen Hristev 
155391b4e487SEugen Hristev 		isc_update_awb_ctrls(isc);
155491b4e487SEugen Hristev 
155591b4e487SEugen Hristev 		mutex_lock(&isc->awb_mutex);
155691b4e487SEugen Hristev 		if (vb2_is_streaming(&isc->vb2_vidq)) {
155791b4e487SEugen Hristev 			/*
155891b4e487SEugen Hristev 			 * If we are streaming, we can update profile to
155991b4e487SEugen Hristev 			 * have the new settings in place.
156091b4e487SEugen Hristev 			 */
156191b4e487SEugen Hristev 			isc_update_profile(isc);
156291b4e487SEugen Hristev 		} else {
156391b4e487SEugen Hristev 			/*
156491b4e487SEugen Hristev 			 * The auto cluster will activate automatically this
156591b4e487SEugen Hristev 			 * control. This has to be deactivated when not
156691b4e487SEugen Hristev 			 * streaming.
156791b4e487SEugen Hristev 			 */
156891b4e487SEugen Hristev 			v4l2_ctrl_activate(isc->do_wb_ctrl, false);
156991b4e487SEugen Hristev 		}
157091b4e487SEugen Hristev 		mutex_unlock(&isc->awb_mutex);
157191b4e487SEugen Hristev 
157291b4e487SEugen Hristev 		/* if we have autowhitebalance on, start histogram procedure */
157391b4e487SEugen Hristev 		if (ctrls->awb == ISC_WB_AUTO &&
157491b4e487SEugen Hristev 		    vb2_is_streaming(&isc->vb2_vidq) &&
157591b4e487SEugen Hristev 		    ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code))
157691b4e487SEugen Hristev 			isc_set_histogram(isc, true);
157791b4e487SEugen Hristev 
157891b4e487SEugen Hristev 		/*
157991b4e487SEugen Hristev 		 * for one time whitebalance adjustment, check the button,
158091b4e487SEugen Hristev 		 * if it's pressed, perform the one time operation.
158191b4e487SEugen Hristev 		 */
158291b4e487SEugen Hristev 		if (ctrls->awb == ISC_WB_NONE &&
158391b4e487SEugen Hristev 		    ctrl->cluster[ISC_CTRL_DO_WB]->is_new &&
158491b4e487SEugen Hristev 		    !(ctrl->cluster[ISC_CTRL_DO_WB]->flags &
158591b4e487SEugen Hristev 		    V4L2_CTRL_FLAG_INACTIVE)) {
158691b4e487SEugen Hristev 			ctrls->awb = ISC_WB_ONETIME;
158791b4e487SEugen Hristev 			isc_set_histogram(isc, true);
158891b4e487SEugen Hristev 			v4l2_dbg(1, debug, &isc->v4l2_dev,
158991b4e487SEugen Hristev 				 "One time white-balance started.\n");
159091b4e487SEugen Hristev 		}
159191b4e487SEugen Hristev 		return 0;
159291b4e487SEugen Hristev 	}
159391b4e487SEugen Hristev 	return 0;
159491b4e487SEugen Hristev }
159591b4e487SEugen Hristev 
159691b4e487SEugen Hristev static int isc_g_volatile_awb_ctrl(struct v4l2_ctrl *ctrl)
159791b4e487SEugen Hristev {
159891b4e487SEugen Hristev 	struct isc_device *isc = container_of(ctrl->handler,
159991b4e487SEugen Hristev 					     struct isc_device, ctrls.handler);
160091b4e487SEugen Hristev 	struct isc_ctrls *ctrls = &isc->ctrls;
160191b4e487SEugen Hristev 
160291b4e487SEugen Hristev 	switch (ctrl->id) {
160391b4e487SEugen Hristev 	/* being a cluster, this id will be called for every control */
160491b4e487SEugen Hristev 	case V4L2_CID_AUTO_WHITE_BALANCE:
160591b4e487SEugen Hristev 		ctrl->cluster[ISC_CTRL_R_GAIN]->val =
160691b4e487SEugen Hristev 					ctrls->gain[ISC_HIS_CFG_MODE_R];
160791b4e487SEugen Hristev 		ctrl->cluster[ISC_CTRL_B_GAIN]->val =
160891b4e487SEugen Hristev 					ctrls->gain[ISC_HIS_CFG_MODE_B];
160991b4e487SEugen Hristev 		ctrl->cluster[ISC_CTRL_GR_GAIN]->val =
161091b4e487SEugen Hristev 					ctrls->gain[ISC_HIS_CFG_MODE_GR];
161191b4e487SEugen Hristev 		ctrl->cluster[ISC_CTRL_GB_GAIN]->val =
161291b4e487SEugen Hristev 					ctrls->gain[ISC_HIS_CFG_MODE_GB];
161391b4e487SEugen Hristev 
161491b4e487SEugen Hristev 		ctrl->cluster[ISC_CTRL_R_OFF]->val =
161591b4e487SEugen Hristev 			ctrls->offset[ISC_HIS_CFG_MODE_R];
161691b4e487SEugen Hristev 		ctrl->cluster[ISC_CTRL_B_OFF]->val =
161791b4e487SEugen Hristev 			ctrls->offset[ISC_HIS_CFG_MODE_B];
161891b4e487SEugen Hristev 		ctrl->cluster[ISC_CTRL_GR_OFF]->val =
161991b4e487SEugen Hristev 			ctrls->offset[ISC_HIS_CFG_MODE_GR];
162091b4e487SEugen Hristev 		ctrl->cluster[ISC_CTRL_GB_OFF]->val =
162191b4e487SEugen Hristev 			ctrls->offset[ISC_HIS_CFG_MODE_GB];
162291b4e487SEugen Hristev 		break;
162391b4e487SEugen Hristev 	}
162491b4e487SEugen Hristev 	return 0;
162591b4e487SEugen Hristev }
162691b4e487SEugen Hristev 
162791b4e487SEugen Hristev static const struct v4l2_ctrl_ops isc_awb_ops = {
162891b4e487SEugen Hristev 	.s_ctrl = isc_s_awb_ctrl,
162991b4e487SEugen Hristev 	.g_volatile_ctrl = isc_g_volatile_awb_ctrl,
163091b4e487SEugen Hristev };
163191b4e487SEugen Hristev 
163291b4e487SEugen Hristev #define ISC_CTRL_OFF(_name, _id, _name_str) \
163391b4e487SEugen Hristev 	static const struct v4l2_ctrl_config _name = { \
163491b4e487SEugen Hristev 		.ops = &isc_awb_ops, \
163591b4e487SEugen Hristev 		.id = _id, \
163691b4e487SEugen Hristev 		.name = _name_str, \
163791b4e487SEugen Hristev 		.type = V4L2_CTRL_TYPE_INTEGER, \
163891b4e487SEugen Hristev 		.flags = V4L2_CTRL_FLAG_SLIDER, \
163991b4e487SEugen Hristev 		.min = -4095, \
164091b4e487SEugen Hristev 		.max = 4095, \
164191b4e487SEugen Hristev 		.step = 1, \
164291b4e487SEugen Hristev 		.def = 0, \
164391b4e487SEugen Hristev 	}
164491b4e487SEugen Hristev 
164591b4e487SEugen Hristev ISC_CTRL_OFF(isc_r_off_ctrl, ISC_CID_R_OFFSET, "Red Component Offset");
164691b4e487SEugen Hristev ISC_CTRL_OFF(isc_b_off_ctrl, ISC_CID_B_OFFSET, "Blue Component Offset");
164791b4e487SEugen Hristev ISC_CTRL_OFF(isc_gr_off_ctrl, ISC_CID_GR_OFFSET, "Green Red Component Offset");
164891b4e487SEugen Hristev ISC_CTRL_OFF(isc_gb_off_ctrl, ISC_CID_GB_OFFSET, "Green Blue Component Offset");
164991b4e487SEugen Hristev 
165091b4e487SEugen Hristev #define ISC_CTRL_GAIN(_name, _id, _name_str) \
165191b4e487SEugen Hristev 	static const struct v4l2_ctrl_config _name = { \
165291b4e487SEugen Hristev 		.ops = &isc_awb_ops, \
165391b4e487SEugen Hristev 		.id = _id, \
165491b4e487SEugen Hristev 		.name = _name_str, \
165591b4e487SEugen Hristev 		.type = V4L2_CTRL_TYPE_INTEGER, \
165691b4e487SEugen Hristev 		.flags = V4L2_CTRL_FLAG_SLIDER, \
165791b4e487SEugen Hristev 		.min = 0, \
165891b4e487SEugen Hristev 		.max = 8191, \
165991b4e487SEugen Hristev 		.step = 1, \
166091b4e487SEugen Hristev 		.def = 512, \
166191b4e487SEugen Hristev 	}
166291b4e487SEugen Hristev 
166391b4e487SEugen Hristev ISC_CTRL_GAIN(isc_r_gain_ctrl, ISC_CID_R_GAIN, "Red Component Gain");
166491b4e487SEugen Hristev ISC_CTRL_GAIN(isc_b_gain_ctrl, ISC_CID_B_GAIN, "Blue Component Gain");
166591b4e487SEugen Hristev ISC_CTRL_GAIN(isc_gr_gain_ctrl, ISC_CID_GR_GAIN, "Green Red Component Gain");
166691b4e487SEugen Hristev ISC_CTRL_GAIN(isc_gb_gain_ctrl, ISC_CID_GB_GAIN, "Green Blue Component Gain");
166791b4e487SEugen Hristev 
166891b4e487SEugen Hristev static int isc_ctrl_init(struct isc_device *isc)
166991b4e487SEugen Hristev {
167091b4e487SEugen Hristev 	const struct v4l2_ctrl_ops *ops = &isc_ctrl_ops;
167191b4e487SEugen Hristev 	struct isc_ctrls *ctrls = &isc->ctrls;
167291b4e487SEugen Hristev 	struct v4l2_ctrl_handler *hdl = &ctrls->handler;
167391b4e487SEugen Hristev 	int ret;
167491b4e487SEugen Hristev 
167591b4e487SEugen Hristev 	ctrls->hist_stat = HIST_INIT;
167691b4e487SEugen Hristev 	isc_reset_awb_ctrls(isc);
167791b4e487SEugen Hristev 
167891b4e487SEugen Hristev 	ret = v4l2_ctrl_handler_init(hdl, 13);
167991b4e487SEugen Hristev 	if (ret < 0)
168091b4e487SEugen Hristev 		return ret;
168191b4e487SEugen Hristev 
168291b4e487SEugen Hristev 	/* Initialize product specific controls. For example, contrast */
168391b4e487SEugen Hristev 	isc->config_ctrls(isc, ops);
168491b4e487SEugen Hristev 
168591b4e487SEugen Hristev 	ctrls->brightness = 0;
168691b4e487SEugen Hristev 
168791b4e487SEugen Hristev 	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -1024, 1023, 1, 0);
168891b4e487SEugen Hristev 	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAMMA, 0, isc->gamma_max, 1,
168991b4e487SEugen Hristev 			  isc->gamma_max);
169091b4e487SEugen Hristev 	isc->awb_ctrl = v4l2_ctrl_new_std(hdl, &isc_awb_ops,
169191b4e487SEugen Hristev 					  V4L2_CID_AUTO_WHITE_BALANCE,
169291b4e487SEugen Hristev 					  0, 1, 1, 1);
169391b4e487SEugen Hristev 
169491b4e487SEugen Hristev 	/* do_white_balance is a button, so min,max,step,default are ignored */
169591b4e487SEugen Hristev 	isc->do_wb_ctrl = v4l2_ctrl_new_std(hdl, &isc_awb_ops,
169691b4e487SEugen Hristev 					    V4L2_CID_DO_WHITE_BALANCE,
169791b4e487SEugen Hristev 					    0, 0, 0, 0);
169891b4e487SEugen Hristev 
169991b4e487SEugen Hristev 	if (!isc->do_wb_ctrl) {
170091b4e487SEugen Hristev 		ret = hdl->error;
170191b4e487SEugen Hristev 		v4l2_ctrl_handler_free(hdl);
170291b4e487SEugen Hristev 		return ret;
170391b4e487SEugen Hristev 	}
170491b4e487SEugen Hristev 
170591b4e487SEugen Hristev 	v4l2_ctrl_activate(isc->do_wb_ctrl, false);
170691b4e487SEugen Hristev 
170791b4e487SEugen Hristev 	isc->r_gain_ctrl = v4l2_ctrl_new_custom(hdl, &isc_r_gain_ctrl, NULL);
170891b4e487SEugen Hristev 	isc->b_gain_ctrl = v4l2_ctrl_new_custom(hdl, &isc_b_gain_ctrl, NULL);
170991b4e487SEugen Hristev 	isc->gr_gain_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gr_gain_ctrl, NULL);
171091b4e487SEugen Hristev 	isc->gb_gain_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gb_gain_ctrl, NULL);
171191b4e487SEugen Hristev 	isc->r_off_ctrl = v4l2_ctrl_new_custom(hdl, &isc_r_off_ctrl, NULL);
171291b4e487SEugen Hristev 	isc->b_off_ctrl = v4l2_ctrl_new_custom(hdl, &isc_b_off_ctrl, NULL);
171391b4e487SEugen Hristev 	isc->gr_off_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gr_off_ctrl, NULL);
171491b4e487SEugen Hristev 	isc->gb_off_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gb_off_ctrl, NULL);
171591b4e487SEugen Hristev 
171691b4e487SEugen Hristev 	/*
171791b4e487SEugen Hristev 	 * The cluster is in auto mode with autowhitebalance enabled
171891b4e487SEugen Hristev 	 * and manual mode otherwise.
171991b4e487SEugen Hristev 	 */
172091b4e487SEugen Hristev 	v4l2_ctrl_auto_cluster(10, &isc->awb_ctrl, 0, true);
172191b4e487SEugen Hristev 
172291b4e487SEugen Hristev 	v4l2_ctrl_handler_setup(hdl);
172391b4e487SEugen Hristev 
172491b4e487SEugen Hristev 	return 0;
172591b4e487SEugen Hristev }
172691b4e487SEugen Hristev 
172791b4e487SEugen Hristev static int isc_async_bound(struct v4l2_async_notifier *notifier,
172891b4e487SEugen Hristev 			   struct v4l2_subdev *subdev,
172991b4e487SEugen Hristev 			   struct v4l2_async_subdev *asd)
173091b4e487SEugen Hristev {
173191b4e487SEugen Hristev 	struct isc_device *isc = container_of(notifier->v4l2_dev,
173291b4e487SEugen Hristev 					      struct isc_device, v4l2_dev);
173391b4e487SEugen Hristev 	struct isc_subdev_entity *subdev_entity =
173491b4e487SEugen Hristev 		container_of(notifier, struct isc_subdev_entity, notifier);
1735*920b2665SEugen Hristev 	int pad;
173691b4e487SEugen Hristev 
173791b4e487SEugen Hristev 	if (video_is_registered(&isc->video_dev)) {
173891b4e487SEugen Hristev 		v4l2_err(&isc->v4l2_dev, "only supports one sub-device.\n");
173991b4e487SEugen Hristev 		return -EBUSY;
174091b4e487SEugen Hristev 	}
174191b4e487SEugen Hristev 
174291b4e487SEugen Hristev 	subdev_entity->sd = subdev;
174391b4e487SEugen Hristev 
1744*920b2665SEugen Hristev 	pad = media_entity_get_fwnode_pad(&subdev->entity, asd->match.fwnode,
1745*920b2665SEugen Hristev 					  MEDIA_PAD_FL_SOURCE);
1746*920b2665SEugen Hristev 	if (pad < 0) {
1747*920b2665SEugen Hristev 		v4l2_err(&isc->v4l2_dev, "failed to find pad for %s\n",
1748*920b2665SEugen Hristev 			 subdev->name);
1749*920b2665SEugen Hristev 		return pad;
1750*920b2665SEugen Hristev 	}
1751*920b2665SEugen Hristev 
1752*920b2665SEugen Hristev 	isc->remote_pad = pad;
1753*920b2665SEugen Hristev 
175491b4e487SEugen Hristev 	return 0;
175591b4e487SEugen Hristev }
175691b4e487SEugen Hristev 
175791b4e487SEugen Hristev static void isc_async_unbind(struct v4l2_async_notifier *notifier,
175891b4e487SEugen Hristev 			     struct v4l2_subdev *subdev,
175991b4e487SEugen Hristev 			     struct v4l2_async_subdev *asd)
176091b4e487SEugen Hristev {
176191b4e487SEugen Hristev 	struct isc_device *isc = container_of(notifier->v4l2_dev,
176291b4e487SEugen Hristev 					      struct isc_device, v4l2_dev);
176391b4e487SEugen Hristev 	mutex_destroy(&isc->awb_mutex);
176491b4e487SEugen Hristev 	cancel_work_sync(&isc->awb_work);
176591b4e487SEugen Hristev 	video_unregister_device(&isc->video_dev);
176691b4e487SEugen Hristev 	v4l2_ctrl_handler_free(&isc->ctrls.handler);
176791b4e487SEugen Hristev }
176891b4e487SEugen Hristev 
1769*920b2665SEugen Hristev struct isc_format *isc_find_format_by_code(struct isc_device *isc,
177091b4e487SEugen Hristev 					   unsigned int code, int *index)
177191b4e487SEugen Hristev {
177291b4e487SEugen Hristev 	struct isc_format *fmt = &isc->formats_list[0];
177391b4e487SEugen Hristev 	unsigned int i;
177491b4e487SEugen Hristev 
177591b4e487SEugen Hristev 	for (i = 0; i < isc->formats_list_size; i++) {
177691b4e487SEugen Hristev 		if (fmt->mbus_code == code) {
177791b4e487SEugen Hristev 			*index = i;
177891b4e487SEugen Hristev 			return fmt;
177991b4e487SEugen Hristev 		}
178091b4e487SEugen Hristev 
178191b4e487SEugen Hristev 		fmt++;
178291b4e487SEugen Hristev 	}
178391b4e487SEugen Hristev 
178491b4e487SEugen Hristev 	return NULL;
178591b4e487SEugen Hristev }
1786*920b2665SEugen Hristev EXPORT_SYMBOL_GPL(isc_find_format_by_code);
178791b4e487SEugen Hristev 
178891b4e487SEugen Hristev static int isc_formats_init(struct isc_device *isc)
178991b4e487SEugen Hristev {
179091b4e487SEugen Hristev 	struct isc_format *fmt;
179191b4e487SEugen Hristev 	struct v4l2_subdev *subdev = isc->current_subdev->sd;
179291b4e487SEugen Hristev 	unsigned int num_fmts, i, j;
179391b4e487SEugen Hristev 	u32 list_size = isc->formats_list_size;
179491b4e487SEugen Hristev 	struct v4l2_subdev_mbus_code_enum mbus_code = {
179591b4e487SEugen Hristev 		.which = V4L2_SUBDEV_FORMAT_ACTIVE,
179691b4e487SEugen Hristev 	};
179791b4e487SEugen Hristev 
179891b4e487SEugen Hristev 	num_fmts = 0;
179991b4e487SEugen Hristev 	while (!v4l2_subdev_call(subdev, pad, enum_mbus_code,
180091b4e487SEugen Hristev 				 NULL, &mbus_code)) {
180191b4e487SEugen Hristev 		mbus_code.index++;
180291b4e487SEugen Hristev 
1803*920b2665SEugen Hristev 		fmt = isc_find_format_by_code(isc, mbus_code.code, &i);
180491b4e487SEugen Hristev 		if (!fmt) {
180591b4e487SEugen Hristev 			v4l2_warn(&isc->v4l2_dev, "Mbus code %x not supported\n",
180691b4e487SEugen Hristev 				  mbus_code.code);
180791b4e487SEugen Hristev 			continue;
180891b4e487SEugen Hristev 		}
180991b4e487SEugen Hristev 
181091b4e487SEugen Hristev 		fmt->sd_support = true;
181191b4e487SEugen Hristev 		num_fmts++;
181291b4e487SEugen Hristev 	}
181391b4e487SEugen Hristev 
181491b4e487SEugen Hristev 	if (!num_fmts)
181591b4e487SEugen Hristev 		return -ENXIO;
181691b4e487SEugen Hristev 
181791b4e487SEugen Hristev 	isc->num_user_formats = num_fmts;
181891b4e487SEugen Hristev 	isc->user_formats = devm_kcalloc(isc->dev,
181991b4e487SEugen Hristev 					 num_fmts, sizeof(*isc->user_formats),
182091b4e487SEugen Hristev 					 GFP_KERNEL);
182191b4e487SEugen Hristev 	if (!isc->user_formats)
182291b4e487SEugen Hristev 		return -ENOMEM;
182391b4e487SEugen Hristev 
182491b4e487SEugen Hristev 	fmt = &isc->formats_list[0];
182591b4e487SEugen Hristev 	for (i = 0, j = 0; i < list_size; i++) {
182691b4e487SEugen Hristev 		if (fmt->sd_support)
182791b4e487SEugen Hristev 			isc->user_formats[j++] = fmt;
182891b4e487SEugen Hristev 		fmt++;
182991b4e487SEugen Hristev 	}
183091b4e487SEugen Hristev 
183191b4e487SEugen Hristev 	return 0;
183291b4e487SEugen Hristev }
183391b4e487SEugen Hristev 
183491b4e487SEugen Hristev static int isc_set_default_fmt(struct isc_device *isc)
183591b4e487SEugen Hristev {
183691b4e487SEugen Hristev 	struct v4l2_format f = {
183791b4e487SEugen Hristev 		.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
183891b4e487SEugen Hristev 		.fmt.pix = {
183991b4e487SEugen Hristev 			.width		= VGA_WIDTH,
184091b4e487SEugen Hristev 			.height		= VGA_HEIGHT,
184191b4e487SEugen Hristev 			.field		= V4L2_FIELD_NONE,
184291b4e487SEugen Hristev 			.pixelformat	= isc->user_formats[0]->fourcc,
184391b4e487SEugen Hristev 		},
184491b4e487SEugen Hristev 	};
184591b4e487SEugen Hristev 	int ret;
184691b4e487SEugen Hristev 
184791b4e487SEugen Hristev 	ret = isc_try_fmt(isc, &f, NULL);
184891b4e487SEugen Hristev 	if (ret)
184991b4e487SEugen Hristev 		return ret;
185091b4e487SEugen Hristev 
185191b4e487SEugen Hristev 	isc->fmt = f;
185291b4e487SEugen Hristev 	return 0;
185391b4e487SEugen Hristev }
185491b4e487SEugen Hristev 
185591b4e487SEugen Hristev static int isc_async_complete(struct v4l2_async_notifier *notifier)
185691b4e487SEugen Hristev {
185791b4e487SEugen Hristev 	struct isc_device *isc = container_of(notifier->v4l2_dev,
185891b4e487SEugen Hristev 					      struct isc_device, v4l2_dev);
185991b4e487SEugen Hristev 	struct video_device *vdev = &isc->video_dev;
186091b4e487SEugen Hristev 	struct vb2_queue *q = &isc->vb2_vidq;
186191b4e487SEugen Hristev 	int ret = 0;
186291b4e487SEugen Hristev 
186391b4e487SEugen Hristev 	INIT_WORK(&isc->awb_work, isc_awb_work);
186491b4e487SEugen Hristev 
186591b4e487SEugen Hristev 	ret = v4l2_device_register_subdev_nodes(&isc->v4l2_dev);
186691b4e487SEugen Hristev 	if (ret < 0) {
186791b4e487SEugen Hristev 		v4l2_err(&isc->v4l2_dev, "Failed to register subdev nodes\n");
186891b4e487SEugen Hristev 		return ret;
186991b4e487SEugen Hristev 	}
187091b4e487SEugen Hristev 
187191b4e487SEugen Hristev 	isc->current_subdev = container_of(notifier,
187291b4e487SEugen Hristev 					   struct isc_subdev_entity, notifier);
187391b4e487SEugen Hristev 	mutex_init(&isc->lock);
187491b4e487SEugen Hristev 	mutex_init(&isc->awb_mutex);
187591b4e487SEugen Hristev 
187691b4e487SEugen Hristev 	init_completion(&isc->comp);
187791b4e487SEugen Hristev 
187891b4e487SEugen Hristev 	/* Initialize videobuf2 queue */
187991b4e487SEugen Hristev 	q->type			= V4L2_BUF_TYPE_VIDEO_CAPTURE;
188091b4e487SEugen Hristev 	q->io_modes		= VB2_MMAP | VB2_DMABUF | VB2_READ;
188191b4e487SEugen Hristev 	q->drv_priv		= isc;
188291b4e487SEugen Hristev 	q->buf_struct_size	= sizeof(struct isc_buffer);
188391b4e487SEugen Hristev 	q->ops			= &isc_vb2_ops;
188491b4e487SEugen Hristev 	q->mem_ops		= &vb2_dma_contig_memops;
188591b4e487SEugen Hristev 	q->timestamp_flags	= V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
188691b4e487SEugen Hristev 	q->lock			= &isc->lock;
188791b4e487SEugen Hristev 	q->min_buffers_needed	= 1;
188891b4e487SEugen Hristev 	q->dev			= isc->dev;
188991b4e487SEugen Hristev 
189091b4e487SEugen Hristev 	ret = vb2_queue_init(q);
189191b4e487SEugen Hristev 	if (ret < 0) {
189291b4e487SEugen Hristev 		v4l2_err(&isc->v4l2_dev,
189391b4e487SEugen Hristev 			 "vb2_queue_init() failed: %d\n", ret);
189491b4e487SEugen Hristev 		goto isc_async_complete_err;
189591b4e487SEugen Hristev 	}
189691b4e487SEugen Hristev 
189791b4e487SEugen Hristev 	/* Init video dma queues */
189891b4e487SEugen Hristev 	INIT_LIST_HEAD(&isc->dma_queue);
189991b4e487SEugen Hristev 	spin_lock_init(&isc->dma_queue_lock);
190091b4e487SEugen Hristev 	spin_lock_init(&isc->awb_lock);
190191b4e487SEugen Hristev 
190291b4e487SEugen Hristev 	ret = isc_formats_init(isc);
190391b4e487SEugen Hristev 	if (ret < 0) {
190491b4e487SEugen Hristev 		v4l2_err(&isc->v4l2_dev,
190591b4e487SEugen Hristev 			 "Init format failed: %d\n", ret);
190691b4e487SEugen Hristev 		goto isc_async_complete_err;
190791b4e487SEugen Hristev 	}
190891b4e487SEugen Hristev 
190991b4e487SEugen Hristev 	ret = isc_set_default_fmt(isc);
191091b4e487SEugen Hristev 	if (ret) {
191191b4e487SEugen Hristev 		v4l2_err(&isc->v4l2_dev, "Could not set default format\n");
191291b4e487SEugen Hristev 		goto isc_async_complete_err;
191391b4e487SEugen Hristev 	}
191491b4e487SEugen Hristev 
191591b4e487SEugen Hristev 	ret = isc_ctrl_init(isc);
191691b4e487SEugen Hristev 	if (ret) {
191791b4e487SEugen Hristev 		v4l2_err(&isc->v4l2_dev, "Init isc ctrols failed: %d\n", ret);
191891b4e487SEugen Hristev 		goto isc_async_complete_err;
191991b4e487SEugen Hristev 	}
192091b4e487SEugen Hristev 
192191b4e487SEugen Hristev 	/* Register video device */
192291b4e487SEugen Hristev 	strscpy(vdev->name, KBUILD_MODNAME, sizeof(vdev->name));
192391b4e487SEugen Hristev 	vdev->release		= video_device_release_empty;
192491b4e487SEugen Hristev 	vdev->fops		= &isc_fops;
192591b4e487SEugen Hristev 	vdev->ioctl_ops		= &isc_ioctl_ops;
192691b4e487SEugen Hristev 	vdev->v4l2_dev		= &isc->v4l2_dev;
192791b4e487SEugen Hristev 	vdev->vfl_dir		= VFL_DIR_RX;
192891b4e487SEugen Hristev 	vdev->queue		= q;
192991b4e487SEugen Hristev 	vdev->lock		= &isc->lock;
193091b4e487SEugen Hristev 	vdev->ctrl_handler	= &isc->ctrls.handler;
193191b4e487SEugen Hristev 	vdev->device_caps	= V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE;
193291b4e487SEugen Hristev 	video_set_drvdata(vdev, isc);
193391b4e487SEugen Hristev 
193491b4e487SEugen Hristev 	ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
193591b4e487SEugen Hristev 	if (ret < 0) {
193691b4e487SEugen Hristev 		v4l2_err(&isc->v4l2_dev,
193791b4e487SEugen Hristev 			 "video_register_device failed: %d\n", ret);
193891b4e487SEugen Hristev 		goto isc_async_complete_err;
193991b4e487SEugen Hristev 	}
194091b4e487SEugen Hristev 
1941*920b2665SEugen Hristev 	ret = isc_scaler_link(isc);
1942*920b2665SEugen Hristev 	if (ret < 0)
1943*920b2665SEugen Hristev 		goto isc_async_complete_unregister_device;
1944*920b2665SEugen Hristev 
1945*920b2665SEugen Hristev 	ret = media_device_register(&isc->mdev);
1946*920b2665SEugen Hristev 	if (ret < 0)
1947*920b2665SEugen Hristev 		goto isc_async_complete_unregister_device;
1948*920b2665SEugen Hristev 
194991b4e487SEugen Hristev 	return 0;
195091b4e487SEugen Hristev 
1951*920b2665SEugen Hristev isc_async_complete_unregister_device:
1952*920b2665SEugen Hristev 	video_unregister_device(vdev);
1953*920b2665SEugen Hristev 
195491b4e487SEugen Hristev isc_async_complete_err:
195591b4e487SEugen Hristev 	mutex_destroy(&isc->awb_mutex);
195691b4e487SEugen Hristev 	mutex_destroy(&isc->lock);
195791b4e487SEugen Hristev 	return ret;
195891b4e487SEugen Hristev }
195991b4e487SEugen Hristev 
196091b4e487SEugen Hristev const struct v4l2_async_notifier_operations microchip_isc_async_ops = {
196191b4e487SEugen Hristev 	.bound = isc_async_bound,
196291b4e487SEugen Hristev 	.unbind = isc_async_unbind,
196391b4e487SEugen Hristev 	.complete = isc_async_complete,
196491b4e487SEugen Hristev };
196591b4e487SEugen Hristev EXPORT_SYMBOL_GPL(microchip_isc_async_ops);
196691b4e487SEugen Hristev 
196791b4e487SEugen Hristev void microchip_isc_subdev_cleanup(struct isc_device *isc)
196891b4e487SEugen Hristev {
196991b4e487SEugen Hristev 	struct isc_subdev_entity *subdev_entity;
197091b4e487SEugen Hristev 
197191b4e487SEugen Hristev 	list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
197291b4e487SEugen Hristev 		v4l2_async_nf_unregister(&subdev_entity->notifier);
197391b4e487SEugen Hristev 		v4l2_async_nf_cleanup(&subdev_entity->notifier);
197491b4e487SEugen Hristev 	}
197591b4e487SEugen Hristev 
197691b4e487SEugen Hristev 	INIT_LIST_HEAD(&isc->subdev_entities);
197791b4e487SEugen Hristev }
197891b4e487SEugen Hristev EXPORT_SYMBOL_GPL(microchip_isc_subdev_cleanup);
197991b4e487SEugen Hristev 
198091b4e487SEugen Hristev int microchip_isc_pipeline_init(struct isc_device *isc)
198191b4e487SEugen Hristev {
198291b4e487SEugen Hristev 	struct device *dev = isc->dev;
198391b4e487SEugen Hristev 	struct regmap *regmap = isc->regmap;
198491b4e487SEugen Hristev 	struct regmap_field *regs;
198591b4e487SEugen Hristev 	unsigned int i;
198691b4e487SEugen Hristev 
198791b4e487SEugen Hristev 	/*
198891b4e487SEugen Hristev 	 * DPCEN-->GDCEN-->BLCEN-->WB-->CFA-->CC-->
198991b4e487SEugen Hristev 	 * GAM-->VHXS-->CSC-->CBC-->SUB422-->SUB420
199091b4e487SEugen Hristev 	 */
199191b4e487SEugen Hristev 	const struct reg_field regfields[ISC_PIPE_LINE_NODE_NUM] = {
199291b4e487SEugen Hristev 		REG_FIELD(ISC_DPC_CTRL, 0, 0),
199391b4e487SEugen Hristev 		REG_FIELD(ISC_DPC_CTRL, 1, 1),
199491b4e487SEugen Hristev 		REG_FIELD(ISC_DPC_CTRL, 2, 2),
199591b4e487SEugen Hristev 		REG_FIELD(ISC_WB_CTRL, 0, 0),
199691b4e487SEugen Hristev 		REG_FIELD(ISC_CFA_CTRL, 0, 0),
199791b4e487SEugen Hristev 		REG_FIELD(ISC_CC_CTRL, 0, 0),
199891b4e487SEugen Hristev 		REG_FIELD(ISC_GAM_CTRL, 0, 0),
199991b4e487SEugen Hristev 		REG_FIELD(ISC_GAM_CTRL, 1, 1),
200091b4e487SEugen Hristev 		REG_FIELD(ISC_GAM_CTRL, 2, 2),
200191b4e487SEugen Hristev 		REG_FIELD(ISC_GAM_CTRL, 3, 3),
200291b4e487SEugen Hristev 		REG_FIELD(ISC_VHXS_CTRL, 0, 0),
200391b4e487SEugen Hristev 		REG_FIELD(ISC_CSC_CTRL + isc->offsets.csc, 0, 0),
200491b4e487SEugen Hristev 		REG_FIELD(ISC_CBC_CTRL + isc->offsets.cbc, 0, 0),
200591b4e487SEugen Hristev 		REG_FIELD(ISC_SUB422_CTRL + isc->offsets.sub422, 0, 0),
200691b4e487SEugen Hristev 		REG_FIELD(ISC_SUB420_CTRL + isc->offsets.sub420, 0, 0),
200791b4e487SEugen Hristev 	};
200891b4e487SEugen Hristev 
200991b4e487SEugen Hristev 	for (i = 0; i < ISC_PIPE_LINE_NODE_NUM; i++) {
201091b4e487SEugen Hristev 		regs = devm_regmap_field_alloc(dev, regmap, regfields[i]);
201191b4e487SEugen Hristev 		if (IS_ERR(regs))
201291b4e487SEugen Hristev 			return PTR_ERR(regs);
201391b4e487SEugen Hristev 
201491b4e487SEugen Hristev 		isc->pipeline[i] =  regs;
201591b4e487SEugen Hristev 	}
201691b4e487SEugen Hristev 
201791b4e487SEugen Hristev 	return 0;
201891b4e487SEugen Hristev }
201991b4e487SEugen Hristev EXPORT_SYMBOL_GPL(microchip_isc_pipeline_init);
202091b4e487SEugen Hristev 
2021*920b2665SEugen Hristev int isc_mc_init(struct isc_device *isc, u32 ver)
2022*920b2665SEugen Hristev {
2023*920b2665SEugen Hristev 	const struct of_device_id *match;
2024*920b2665SEugen Hristev 	int ret;
2025*920b2665SEugen Hristev 
2026*920b2665SEugen Hristev 	isc->video_dev.entity.function = MEDIA_ENT_F_IO_V4L;
2027*920b2665SEugen Hristev 	isc->video_dev.entity.flags = MEDIA_ENT_FL_DEFAULT;
2028*920b2665SEugen Hristev 	isc->pads[ISC_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
2029*920b2665SEugen Hristev 
2030*920b2665SEugen Hristev 	ret = media_entity_pads_init(&isc->video_dev.entity, ISC_PADS_NUM,
2031*920b2665SEugen Hristev 				     isc->pads);
2032*920b2665SEugen Hristev 	if (ret < 0) {
2033*920b2665SEugen Hristev 		dev_err(isc->dev, "media entity init failed\n");
2034*920b2665SEugen Hristev 		return ret;
2035*920b2665SEugen Hristev 	}
2036*920b2665SEugen Hristev 
2037*920b2665SEugen Hristev 	isc->mdev.dev = isc->dev;
2038*920b2665SEugen Hristev 
2039*920b2665SEugen Hristev 	match = of_match_node(isc->dev->driver->of_match_table,
2040*920b2665SEugen Hristev 			      isc->dev->of_node);
2041*920b2665SEugen Hristev 
2042*920b2665SEugen Hristev 	strscpy(isc->mdev.driver_name, KBUILD_MODNAME,
2043*920b2665SEugen Hristev 		sizeof(isc->mdev.driver_name));
2044*920b2665SEugen Hristev 	strscpy(isc->mdev.model, match->compatible, sizeof(isc->mdev.model));
2045*920b2665SEugen Hristev 	snprintf(isc->mdev.bus_info, sizeof(isc->mdev.bus_info), "platform:%s",
2046*920b2665SEugen Hristev 		 isc->v4l2_dev.name);
2047*920b2665SEugen Hristev 	isc->mdev.hw_revision = ver;
2048*920b2665SEugen Hristev 
2049*920b2665SEugen Hristev 	media_device_init(&isc->mdev);
2050*920b2665SEugen Hristev 
2051*920b2665SEugen Hristev 	isc->v4l2_dev.mdev = &isc->mdev;
2052*920b2665SEugen Hristev 
2053*920b2665SEugen Hristev 	return isc_scaler_init(isc);
2054*920b2665SEugen Hristev }
2055*920b2665SEugen Hristev EXPORT_SYMBOL_GPL(isc_mc_init);
2056*920b2665SEugen Hristev 
2057*920b2665SEugen Hristev void isc_mc_cleanup(struct isc_device *isc)
2058*920b2665SEugen Hristev {
2059*920b2665SEugen Hristev 	media_entity_cleanup(&isc->video_dev.entity);
2060*920b2665SEugen Hristev 	media_device_cleanup(&isc->mdev);
2061*920b2665SEugen Hristev }
2062*920b2665SEugen Hristev EXPORT_SYMBOL_GPL(isc_mc_cleanup);
2063*920b2665SEugen Hristev 
206491b4e487SEugen Hristev /* regmap configuration */
206591b4e487SEugen Hristev #define MICROCHIP_ISC_REG_MAX    0xd5c
206691b4e487SEugen Hristev const struct regmap_config microchip_isc_regmap_config = {
206791b4e487SEugen Hristev 	.reg_bits       = 32,
206891b4e487SEugen Hristev 	.reg_stride     = 4,
206991b4e487SEugen Hristev 	.val_bits       = 32,
207091b4e487SEugen Hristev 	.max_register	= MICROCHIP_ISC_REG_MAX,
207191b4e487SEugen Hristev };
207291b4e487SEugen Hristev EXPORT_SYMBOL_GPL(microchip_isc_regmap_config);
207391b4e487SEugen Hristev 
207491b4e487SEugen Hristev MODULE_AUTHOR("Songjun Wu");
207591b4e487SEugen Hristev MODULE_AUTHOR("Eugen Hristev");
207691b4e487SEugen Hristev MODULE_DESCRIPTION("Microchip ISC common code base");
207791b4e487SEugen Hristev MODULE_LICENSE("GPL v2");
2078