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