From: Sakari Ailus <sakari.ailus@linux.intel.com>
To: Marek Vasut <marex@denx.de>
Cc: linux-media@vger.kernel.org,
Mauro Carvalho Chehab <mchehab+samsung@kernel.org>,
Rob Herring <robh+dt@kernel.org>
Subject: Re: [PATCH 2/2] media: i2c: isl7998x: Add driver for Intersil ISL7998x
Date: Mon, 1 Jul 2019 11:43:15 +0300 [thread overview]
Message-ID: <20190701084315.eygyytirydies422@paasikivi.fi.intel.com> (raw)
In-Reply-To: <20190520201812.7937-2-marex@denx.de>
Hi Marek,
Thank you for the patchset --- and my apologies for reviewing it so late.
On Mon, May 20, 2019 at 10:18:12PM +0200, Marek Vasut wrote:
> Add driver for the Intersil ISL7998x BT656-to-MIPI-CSI2 video decoder.
> This chip supports 1/2/4 analog video inputs and converts them into
> 1/2/4 VCs in MIPI CSI2 stream.
>
> This driver currently supports ISL79987 and both 720x480 and 720x576
> resolutions, however as per specification, all inputs must use the
> same resolution and standard. The only supported pixel format is now
> YUYV/YUV422. The chip should support RGB565 on the CSI2 as well, but
> this is currently unsupported.
>
> Signed-off-by: Marek Vasut <marex@denx.de>
> Cc: Sakari Ailus <sakari.ailus@linux.intel.com>
> Cc: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
> Cc: Rob Herring <robh+dt@kernel.org>
> To: linux-media@vger.kernel.org
> ---
> drivers/media/i2c/Kconfig | 6 +
> drivers/media/i2c/Makefile | 1 +
> drivers/media/i2c/isl7998x.c | 1111 ++++++++++++++++++++++++++++++++++
> 3 files changed, 1118 insertions(+)
> create mode 100644 drivers/media/i2c/isl7998x.c
>
> diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
> index 7793358ab8b3..af2ea08d6c59 100644
> --- a/drivers/media/i2c/Kconfig
> +++ b/drivers/media/i2c/Kconfig
> @@ -929,6 +929,12 @@ config VIDEO_NOON010PC30
> help
> This driver supports NOON010PC30 CIF camera from Siliconfile
>
> +config VIDEO_ISL7998X
> + tristate "Intersil ISL7998x support"
> + depends on I2C && VIDEO_V4L2
> + help
> + This driver supports Intersil ISL7998x BT656-to-MIPI-CSI2 bridge.
> +
> source "drivers/media/i2c/m5mols/Kconfig"
>
> config VIDEO_RJ54N1
> diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
> index d8ad9dad495d..a66f105a7bcc 100644
> --- a/drivers/media/i2c/Makefile
> +++ b/drivers/media/i2c/Makefile
> @@ -113,6 +113,7 @@ obj-$(CONFIG_VIDEO_IMX258) += imx258.o
> obj-$(CONFIG_VIDEO_IMX274) += imx274.o
> obj-$(CONFIG_VIDEO_IMX319) += imx319.o
> obj-$(CONFIG_VIDEO_IMX355) += imx355.o
> +obj-$(CONFIG_VIDEO_ISL7998X) += isl7998x.o
> obj-$(CONFIG_VIDEO_ST_MIPID02) += st-mipid02.o
>
> obj-$(CONFIG_SDR_MAX2175) += max2175.o
> diff --git a/drivers/media/i2c/isl7998x.c b/drivers/media/i2c/isl7998x.c
> new file mode 100644
> index 000000000000..858e98d8b494
> --- /dev/null
> +++ b/drivers/media/i2c/isl7998x.c
> @@ -0,0 +1,1111 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Intersil ISL7998x BT656-to-MIPI-CSI2 driver
> + *
> + * Copyright (C) 2018-2019 Marek Vasut <marex@denx.de>
> + */
> +#include <linux/videodev2.h>
> +#include <linux/delay.h>
> +#include <linux/gpio.h>
> +#include <linux/i2c.h>
> +#include <linux/log2.h>
> +#include <linux/module.h>
> +#include <linux/of_graph.h>
> +#include <linux/regmap.h>
> +#include <linux/slab.h>
> +#include <linux/v4l2-mediabus.h>
> +#include <media/v4l2-async.h>
> +#include <media/v4l2-clk.h>
> +#include <media/v4l2-common.h>
> +#include <media/v4l2-ctrls.h>
> +#include <media/v4l2-device.h>
> +#include <media/v4l2-fwnode.h>
Alphabetical order, please.
> +
> +#define ISL7998x_WIDTH 720
> +#define ISL7998x_HEIGHT 480
> +#define ISL7998x_INPUTS 4
> +
> +#define V4L2_CID_TEST_PATTERN_COLOR (V4L2_CID_USER_BASE | 0x1001)
> +#define V4L2_CID_TEST_PATTERN_CHANNELS (V4L2_CID_USER_BASE | 0x1002)
> +#define V4L2_CID_TEST_PATTERN_BARS (V4L2_CID_USER_BASE | 0x1003)
> +
> +#define ISL7998x_REG(page, reg) (((page) << 8) | (reg))
> +
> +#define ISL7998x_REG_Pn_SIZE 256
> +#define ISL7998x_REG_Pn_BASE(n) ((n) * ISL7998x_REG_Pn_SIZE)
> +
> +#define ISL7998x_REG_Px_DEC_PAGE(page) ISL7998x_REG((page), 0xff)
> +#define ISL7998x_REG_Px_DEC_PAGE_MASK 0xf
> +#define ISL7998x_REG_P0_PRODUCT_ID_CODE ISL7998x_REG(0, 0x00)
> +#define ISL7998x_REG_P0_PRODUCT_REV_CODE ISL7998x_REG(0, 0x01)
> +#define ISL7998x_REG_P0_SW_RESET_CTL ISL7998x_REG(0, 0x02)
> +#define ISL7998x_REG_P0_IO_BUFFER_CTL ISL7998x_REG(0, 0x03)
> +#define ISL7998x_REG_P0_IO_BUFFER_CTL_1_1 ISL7998x_REG(0, 0x04)
> +#define ISL7998x_REG_P0_IO_PAD_PULL_EN_CTL ISL7998x_REG(0, 0x05)
> +#define ISL7998x_REG_P0_IO_BUFFER_CTL_1_2 ISL7998x_REG(0, 0x06)
> +#define ISL7998x_REG_P0_VIDEO_IN_CHAN_CTL ISL7998x_REG(0, 0x07)
> +#define ISL7998x_REG_P0_CLK_CTL_1 ISL7998x_REG(0, 0x08)
> +#define ISL7998x_REG_P0_CLK_CTL_2 ISL7998x_REG(0, 0x09)
> +#define ISL7998x_REG_P0_CLK_CTL_3 ISL7998x_REG(0, 0x0a)
> +#define ISL7998x_REG_P0_CLK_CTL_4 ISL7998x_REG(0, 0x0b)
> +#define ISL7998x_REG_P0_MPP1_SYNC_CTL ISL7998x_REG(0, 0x0c)
> +#define ISL7998x_REG_P0_MPP2_SYNC_CTL ISL7998x_REG(0, 0x0d)
> +#define ISL7998x_REG_P0_IRQ_SYNC_CTL ISL7998x_REG(0, 0x0e)
> +#define ISL7998x_REG_P0_INTERRUPT_STATUS ISL7998x_REG(0, 0x10)
> +#define ISL7998x_REG_P0_CHAN_1_IRQ ISL7998x_REG(0, 0x11)
> +#define ISL7998x_REG_P0_CHAN_2_IRQ ISL7998x_REG(0, 0x12)
> +#define ISL7998x_REG_P0_CHAN_3_IRQ ISL7998x_REG(0, 0x13)
> +#define ISL7998x_REG_P0_CHAN_4_IRQ ISL7998x_REG(0, 0x14)
> +#define ISL7998x_REG_P0_SHORT_DIAG_IRQ ISL7998x_REG(0, 0x15)
> +#define ISL7998x_REG_P0_CHAN_1_IRQ_EN ISL7998x_REG(0, 0x16)
> +#define ISL7998x_REG_P0_CHAN_2_IRQ_EN ISL7998x_REG(0, 0x17)
> +#define ISL7998x_REG_P0_CHAN_3_IRQ_EN ISL7998x_REG(0, 0x18)
> +#define ISL7998x_REG_P0_CHAN_4_IRQ_EN ISL7998x_REG(0, 0x19)
> +#define ISL7998x_REG_P0_SHORT_DIAG_IRQ_EN ISL7998x_REG(0, 0x1a)
> +#define ISL7998x_REG_P0_CHAN_1_STATUS ISL7998x_REG(0, 0x1b)
> +#define ISL7998x_REG_P0_CHAN_2_STATUS ISL7998x_REG(0, 0x1c)
> +#define ISL7998x_REG_P0_CHAN_3_STATUS ISL7998x_REG(0, 0x1d)
> +#define ISL7998x_REG_P0_CHAN_4_STATUS ISL7998x_REG(0, 0x1e)
> +#define ISL7998x_REG_P0_SHORT_DIAG_STATUS ISL7998x_REG(0, 0x1f)
> +#define ISL7998x_REG_P0_CLOCK_DELAY ISL7998x_REG(0, 0x20)
> +
> +#define ISL7998x_REG_Px_DEC_INPUT_FMT(pg) ISL7998x_REG((pg), 0x02)
> +#define ISL7998x_REG_Px_DEC_STATUS_1(pg) ISL7998x_REG((pg), 0x03)
> +#define ISL7998x_REG_Px_DEC_HS_DELAY_CTL(pg) ISL7998x_REG((pg), 0x04)
> +#define ISL7998x_REG_Px_DEC_ANCTL(pg) ISL7998x_REG((pg), 0x06)
> +#define ISL7998x_REG_Px_DEC_CROP_HI(pg) ISL7998x_REG((pg), 0x07)
> +#define ISL7998x_REG_Px_DEC_VDELAY_LO(pg) ISL7998x_REG((pg), 0x08)
> +#define ISL7998x_REG_Px_DEC_VACTIVE_LO(pg) ISL7998x_REG((pg), 0x09)
> +#define ISL7998x_REG_Px_DEC_HDELAY_LO(pg) ISL7998x_REG((pg), 0x0a)
> +#define ISL7998x_REG_Px_DEC_HACTIVE_LO(pg) ISL7998x_REG((pg), 0x0b)
> +#define ISL7998x_REG_Px_DEC_CNTRL1(pg) ISL7998x_REG((pg), 0x0c)
> +#define ISL7998x_REG_Px_DEC_CSC_CTL(pg) ISL7998x_REG((pg), 0x0d)
> +#define ISL7998x_REG_Px_DEC_BRIGHT(pg) ISL7998x_REG((pg), 0x10)
> +#define ISL7998x_REG_Px_DEC_CONTRAST(pg) ISL7998x_REG((pg), 0x11)
> +#define ISL7998x_REG_Px_DEC_SHARPNESS(pg) ISL7998x_REG((pg), 0x12)
> +#define ISL7998x_REG_Px_DEC_SAT_U(pg) ISL7998x_REG((pg), 0x13)
> +#define ISL7998x_REG_Px_DEC_SAT_V(pg) ISL7998x_REG((pg), 0x14)
> +#define ISL7998x_REG_Px_DEC_HUE(pg) ISL7998x_REG((pg), 0x15)
> +#define ISL7998x_REG_Px_DEC_VERT_PEAK(pg) ISL7998x_REG((pg), 0x17)
> +#define ISL7998x_REG_Px_DEC_CORING(pg) ISL7998x_REG((pg), 0x18)
> +#define ISL7998x_REG_Px_DEC_SDT(pg) ISL7998x_REG((pg), 0x1c)
> +#define ISL7998x_REG_Px_DEC_SDT_DET BIT(7)
> +#define ISL7998x_REG_Px_DEC_SDTR(pg) ISL7998x_REG((pg), 0x1d)
> +#define ISL7998x_REG_Px_DEC_CLMPG(pg) ISL7998x_REG((pg), 0x20)
> +#define ISL7998x_REG_Px_DEC_IAGC(pg) ISL7998x_REG((pg), 0x21)
> +#define ISL7998x_REG_Px_DEC_AGCGAIN(pg) ISL7998x_REG((pg), 0x22)
> +#define ISL7998x_REG_Px_DEC_PEAKWT(pg) ISL7998x_REG((pg), 0x23)
> +#define ISL7998x_REG_Px_DEC_CLMPL(pg) ISL7998x_REG((pg), 0x24)
> +#define ISL7998x_REG_Px_DEC_SYNCT(pg) ISL7998x_REG((pg), 0x25)
> +#define ISL7998x_REG_Px_DEC_MISSCNT(pg) ISL7998x_REG((pg), 0x26)
> +#define ISL7998x_REG_Px_DEC_PCLAMP(pg) ISL7998x_REG((pg), 0x27)
> +#define ISL7998x_REG_Px_DEC_VERT_CTL_1(pg) ISL7998x_REG((pg), 0x28)
> +#define ISL7998x_REG_Px_DEC_VERT_CTL_2(pg) ISL7998x_REG((pg), 0x29)
> +#define ISL7998x_REG_Px_DEC_CLR_KILL_LVL(pg) ISL7998x_REG((pg), 0x2a)
> +#define ISL7998x_REG_Px_DEC_COMB_FILTER_CTL(pg) ISL7998x_REG((pg), 0x2b)
> +#define ISL7998x_REG_Px_DEC_LUMA_DELAY(pg) ISL7998x_REG((pg), 0x2c)
> +#define ISL7998x_REG_Px_DEC_MISC1(pg) ISL7998x_REG((pg), 0x2d)
> +#define ISL7998x_REG_Px_DEC_MISC2(pg) ISL7998x_REG((pg), 0x2e)
> +#define ISL7998x_REG_Px_DEC_MISC3(pg) ISL7998x_REG((pg), 0x2f)
> +#define ISL7998x_REG_Px_DEC_MVSN(pg) ISL7998x_REG((pg), 0x30)
> +#define ISL7998x_REG_Px_DEC_CSTATUS2(pg) ISL7998x_REG((pg), 0x31)
> +#define ISL7998x_REG_Px_DEC_HFREF(pg) ISL7998x_REG((pg), 0x32)
> +#define ISL7998x_REG_Px_DEC_CLMD(pg) ISL7998x_REG((pg), 0x33)
> +#define ISL7998x_REG_Px_DEC_ID_DET_CTL(pg) ISL7998x_REG((pg), 0x34)
> +#define ISL7998x_REG_Px_DEC_CLCNTL(pg) ISL7998x_REG((pg), 0x35)
> +#define ISL7998x_REG_Px_DEC_DIFF_CLMP_CTL_1(pg) ISL7998x_REG((pg), 0x36)
> +#define ISL7998x_REG_Px_DEC_DIFF_CLMP_CTL_2(pg) ISL7998x_REG((pg), 0x37)
> +#define ISL7998x_REG_Px_DEC_DIFF_CLMP_CTL_3(pg) ISL7998x_REG((pg), 0x38)
> +#define ISL7998x_REG_Px_DEC_DIFF_CLMP_CTL_4(pg) ISL7998x_REG((pg), 0x39)
> +#define ISL7998x_REG_Px_DEC_SHORT_DET_CTL(pg) ISL7998x_REG((pg), 0x3a)
> +#define ISL7998x_REG_Px_DEC_SHORT_DET_CTL_1(pg) ISL7998x_REG((pg), 0x3b)
> +#define ISL7998x_REG_Px_DEC_AFE_TST_MUX_CTL(pg) ISL7998x_REG((pg), 0x3c)
> +#define ISL7998x_REG_Px_DEC_DATA_CONV(pg) ISL7998x_REG((pg), 0x3d)
> +#define ISL7998x_REG_Px_DEC_INTERNAL_TEST(pg) ISL7998x_REG((pg), 0x3f)
> +#define ISL7998x_REG_Px_DEC_H_DELAY_CTL(pg) ISL7998x_REG((pg), 0x43)
> +#define ISL7998x_REG_Px_DEC_H_DELAY_II_HI(pg) ISL7998x_REG((pg), 0x44)
> +#define ISL7998x_REG_Px_DEC_H_DELAY_II_LOW(pg) ISL7998x_REG((pg), 0x45)
> +
> +#define ISL7998x_REG_Px_ACA_CTL_1(pg) ISL7998x_REG((pg), 0x80)
> +#define ISL7998x_REG_Px_ACA_GAIN_CTL(pg) ISL7998x_REG((pg), 0x81)
> +#define ISL7998x_REG_Px_ACA_Y_AVG_HI_LIMIT(pg) ISL7998x_REG((pg), 0x82)
> +#define ISL7998x_REG_Px_ACA_Y_AVG_LO_LIMIT(pg) ISL7998x_REG((pg), 0x83)
> +#define ISL7998x_REG_Px_ACA_Y_DET_THRESHOLD(pg) ISL7998x_REG((pg), 0x84)
> +#define ISL7998x_REG_Px_ACA_BLACK_LVL(pg) ISL7998x_REG((pg), 0x85)
> +#define ISL7998x_REG_Px_ACA_CENTER_LVL(pg) ISL7998x_REG((pg), 0x86)
> +#define ISL7998x_REG_Px_ACA_WHITE_LVL(pg) ISL7998x_REG((pg), 0x87)
> +#define ISL7998x_REG_Px_ACA_MEAN_OFF_LIMIT(pg) ISL7998x_REG((pg), 0x88)
> +#define ISL7998x_REG_Px_ACA_MEAN_OFF_UPGAIN(pg) ISL7998x_REG((pg), 0x89)
> +#define ISL7998x_REG_Px_ACA_MEAN_OFF_SLOPE(pg) ISL7998x_REG((pg), 0x8a)
> +#define ISL7998x_REG_Px_ACA_MEAN_OFF_DNGAIN(pg) ISL7998x_REG((pg), 0x8b)
> +#define ISL7998x_REG_Px_ACA_DELTA_CO_THRES(pg) ISL7998x_REG((pg), 0x8c)
> +#define ISL7998x_REG_Px_ACA_DELTA_SLOPE(pg) ISL7998x_REG((pg), 0x8d)
> +#define ISL7998x_REG_Px_ACA_LO_HI_AVG_THRES(pg) ISL7998x_REG((pg), 0x8e)
> +#define ISL7998x_REG_Px_ACA_LO_MAX_LVL_CTL(pg) ISL7998x_REG((pg), 0x8f)
> +#define ISL7998x_REG_Px_ACA_HI_MAX_LVL_CTL(pg) ISL7998x_REG((pg), 0x90)
> +#define ISL7998x_REG_Px_ACA_LO_UPGAIN_CTL(pg) ISL7998x_REG((pg), 0x91)
> +#define ISL7998x_REG_Px_ACA_LO_DNGAIN_CTL(pg) ISL7998x_REG((pg), 0x92)
> +#define ISL7998x_REG_Px_ACA_HI_UPGAIN_CTL(pg) ISL7998x_REG((pg), 0x93)
> +#define ISL7998x_REG_Px_ACA_HI_DNGAIN_CTL(pg) ISL7998x_REG((pg), 0x94)
> +#define ISL7998x_REG_Px_ACA_LOPASS_FLT_COEF(pg) ISL7998x_REG((pg), 0x95)
> +#define ISL7998x_REG_Px_ACA_PDF_INDEX(pg) ISL7998x_REG((pg), 0x96)
> +#define ISL7998x_REG_Px_ACA_HIST_WIN_H_STT(pg) ISL7998x_REG((pg), 0x97)
> +#define ISL7998x_REG_Px_ACA_HIST_WIN_H_SZ1(pg) ISL7998x_REG((pg), 0x98)
> +#define ISL7998x_REG_Px_ACA_HIST_WIN_H_SZ2(pg) ISL7998x_REG((pg), 0x99)
> +#define ISL7998x_REG_Px_ACA_HIST_WIN_V_STT(pg) ISL7998x_REG((pg), 0x9a)
> +#define ISL7998x_REG_Px_ACA_HIST_WIN_V_SZ1(pg) ISL7998x_REG((pg), 0x9b)
> +#define ISL7998x_REG_Px_ACA_HIST_WIN_V_SZ2(pg) ISL7998x_REG((pg), 0x9c)
> +#define ISL7998x_REG_Px_ACA_Y_AVG(pg) ISL7998x_REG((pg), 0xa0)
> +#define ISL7998x_REG_Px_ACA_Y_AVG_LIM(pg) ISL7998x_REG((pg), 0xa1)
> +#define ISL7998x_REG_Px_ACA_LO_AVG(pg) ISL7998x_REG((pg), 0xa2)
> +#define ISL7998x_REG_Px_ACA_HI_AVG(pg) ISL7998x_REG((pg), 0xa3)
> +#define ISL7998x_REG_Px_ACA_Y_MAX(pg) ISL7998x_REG((pg), 0xa4)
> +#define ISL7998x_REG_Px_ACA_Y_MIN(pg) ISL7998x_REG((pg), 0xa5)
> +#define ISL7998x_REG_Px_ACA_MOFFSET(pg) ISL7998x_REG((pg), 0xa6)
> +#define ISL7998x_REG_Px_ACA_LO_GAIN(pg) ISL7998x_REG((pg), 0xa7)
> +#define ISL7998x_REG_Px_ACA_HI_GAIN(pg) ISL7998x_REG((pg), 0xa8)
> +#define ISL7998x_REG_Px_ACA_LL_SLOPE(pg) ISL7998x_REG((pg), 0xa9)
> +#define ISL7998x_REG_Px_ACA_LH_SLOPE(pg) ISL7998x_REG((pg), 0xaa)
> +#define ISL7998x_REG_Px_ACA_HL_SLOPE(pg) ISL7998x_REG((pg), 0xab)
> +#define ISL7998x_REG_Px_ACA_HH_SLOPE(pg) ISL7998x_REG((pg), 0xac)
> +#define ISL7998x_REG_Px_ACA_X_LOW(pg) ISL7998x_REG((pg), 0xad)
> +#define ISL7998x_REG_Px_ACA_X_MEAN(pg) ISL7998x_REG((pg), 0xae)
> +#define ISL7998x_REG_Px_ACA_X_HIGH(pg) ISL7998x_REG((pg), 0xaf)
> +#define ISL7998x_REG_Px_ACA_Y_LOW(pg) ISL7998x_REG((pg), 0xb0)
> +#define ISL7998x_REG_Px_ACA_Y_MEAN(pg) ISL7998x_REG((pg), 0xb1)
> +#define ISL7998x_REG_Px_ACA_Y_HIGH(pg) ISL7998x_REG((pg), 0xb2)
> +#define ISL7998x_REG_Px_ACA_CTL_2(pg) ISL7998x_REG((pg), 0xb3)
> +#define ISL7998x_REG_Px_ACA_CTL_3(pg) ISL7998x_REG((pg), 0xb4)
> +#define ISL7998x_REG_Px_ACA_CTL_4(pg) ISL7998x_REG((pg), 0xb5)
> +#define ISL7998x_REG_Px_ACA_FLEX_WIN_HIST(pg) ISL7998x_REG((pg), 0xc0)
> +#define ISL7998x_REG_Px_ACA_FLEX_WIN_X_TL_H(pg) ISL7998x_REG((pg), 0xc1)
> +#define ISL7998x_REG_Px_ACA_FLEX_WIN_X_TL_L(pg) ISL7998x_REG((pg), 0xc2)
> +#define ISL7998x_REG_Px_ACA_FLEX_WIN_Y_TL_H(pg) ISL7998x_REG((pg), 0xc3)
> +#define ISL7998x_REG_Px_ACA_FLEX_WIN_Y_TL_L(pg) ISL7998x_REG((pg), 0xc4)
> +#define ISL7998x_REG_Px_ACA_FLEX_WIN_X_TR_H(pg) ISL7998x_REG((pg), 0xc5)
> +#define ISL7998x_REG_Px_ACA_FLEX_WIN_X_TR_L(pg) ISL7998x_REG((pg), 0xc6)
> +#define ISL7998x_REG_Px_ACA_FLEX_WIN_Y_TR_H(pg) ISL7998x_REG((pg), 0xc7)
> +#define ISL7998x_REG_Px_ACA_FLEX_WIN_Y_TR_L(pg) ISL7998x_REG((pg), 0xc8)
> +#define ISL7998x_REG_Px_ACA_FLEX_WIN_X_BL_H(pg) ISL7998x_REG((pg), 0xc9)
> +#define ISL7998x_REG_Px_ACA_FLEX_WIN_X_BL_L(pg) ISL7998x_REG((pg), 0xca)
> +#define ISL7998x_REG_Px_ACA_FLEX_WIN_Y_BL_H(pg) ISL7998x_REG((pg), 0xcb)
> +#define ISL7998x_REG_Px_ACA_FLEX_WIN_Y_BL_L(pg) ISL7998x_REG((pg), 0xcc)
> +#define ISL7998x_REG_Px_ACA_FLEX_WIN_X_BR_H(pg) ISL7998x_REG((pg), 0xcd)
> +#define ISL7998x_REG_Px_ACA_FLEX_WIN_X_BR_L(pg) ISL7998x_REG((pg), 0xce)
> +#define ISL7998x_REG_Px_ACA_FLEX_WIN_Y_BR_H(pg) ISL7998x_REG((pg), 0xcf)
> +#define ISL7998x_REG_Px_ACA_FLEX_WIN_Y_BR_L(pg) ISL7998x_REG((pg), 0xd0)
> +#define ISL7998x_REG_Px_ACA_FLEX_WIN_X_LM_H(pg) ISL7998x_REG((pg), 0xd1)
> +#define ISL7998x_REG_Px_ACA_FLEX_WIN_X_LM_L(pg) ISL7998x_REG((pg), 0xd2)
> +#define ISL7998x_REG_Px_ACA_FLEX_WIN_Y_LM_H(pg) ISL7998x_REG((pg), 0xd3)
> +#define ISL7998x_REG_Px_ACA_FLEX_WIN_Y_LM_L(pg) ISL7998x_REG((pg), 0xd4)
> +#define ISL7998x_REG_Px_ACA_FLEX_WIN_X_TM_H(pg) ISL7998x_REG((pg), 0xd5)
> +#define ISL7998x_REG_Px_ACA_FLEX_WIN_X_TM_L(pg) ISL7998x_REG((pg), 0xd6)
> +#define ISL7998x_REG_Px_ACA_FLEX_WIN_Y_TM_H(pg) ISL7998x_REG((pg), 0xd7)
> +#define ISL7998x_REG_Px_ACA_FLEX_WIN_Y_TM_L(pg) ISL7998x_REG((pg), 0xd8)
> +#define ISL7998x_REG_Px_ACA_FLEX_WIN_X_BM_H(pg) ISL7998x_REG((pg), 0xd9)
> +#define ISL7998x_REG_Px_ACA_FLEX_WIN_X_BM_L(pg) ISL7998x_REG((pg), 0xda)
> +#define ISL7998x_REG_Px_ACA_FLEX_WIN_Y_BM_H(pg) ISL7998x_REG((pg), 0xdb)
> +#define ISL7998x_REG_Px_ACA_FLEX_WIN_Y_BM_L(pg) ISL7998x_REG((pg), 0xdc)
> +#define ISL7998x_REG_Px_ACA_FLEX_WIN_X_RM_H(pg) ISL7998x_REG((pg), 0xdd)
> +#define ISL7998x_REG_Px_ACA_FLEX_WIN_X_RM_L(pg) ISL7998x_REG((pg), 0xde)
> +#define ISL7998x_REG_Px_ACA_FLEX_WIN_Y_RM_H(pg) ISL7998x_REG((pg), 0xdf)
> +#define ISL7998x_REG_Px_ACA_FLEX_WIN_Y_RM_L(pg) ISL7998x_REG((pg), 0xe0)
> +#define ISL7998x_REG_Px_ACA_HIST_DATA_LO(pg) ISL7998x_REG((pg), 0xe1)
> +#define ISL7998x_REG_Px_ACA_HIST_DATA_MID(pg) ISL7998x_REG((pg), 0xe2)
> +#define ISL7998x_REG_Px_ACA_HIST_DATA_HI(pg) ISL7998x_REG((pg), 0xe3)
> +#define ISL7998x_REG_Px_ACA_FLEX_WIN_Y_CLR(pg) ISL7998x_REG((pg), 0xe4)
> +#define ISL7998x_REG_Px_ACA_FLEX_WIN_CB_CLR(pg) ISL7998x_REG((pg), 0xe5)
> +#define ISL7998x_REG_Px_ACA_FLEX_WIN_CR_CLR(pg) ISL7998x_REG((pg), 0xe6)
> +#define ISL7998x_REG_Px_ACA_XFER_HIST_HOST(pg) ISL7998x_REG((pg), 0xe7)
> +
> +#define ISL7998x_REG_P5_LI_ENGINE_CTL ISL7998x_REG(5, 0x00)
> +#define ISL7998x_REG_P5_LI_ENGINE_LINE_CTL ISL7998x_REG(5, 0x01)
> +#define ISL7998x_REG_P5_LI_ENGINE_PIC_WIDTH ISL7998x_REG(5, 0x02)
> +#define ISL7998x_REG_P5_LI_ENGINE_SYNC_CTL ISL7998x_REG(5, 0x03)
> +#define ISL7998x_REG_P5_LI_ENGINE_VC_ASSIGNMENT ISL7998x_REG(5, 0x04)
> +#define ISL7998x_REG_P5_LI_ENGINE_TYPE_CTL ISL7998x_REG(5, 0x05)
> +#define ISL7998x_REG_P5_LI_ENGINE_FIFO_CTL ISL7998x_REG(5, 0x06)
> +#define ISL7998x_REG_P5_MIPI_READ_START_CTL ISL7998x_REG(5, 0x07)
> +#define ISL7998x_REG_P5_PSEUDO_FRM_FIELD_CTL ISL7998x_REG(5, 0x08)
> +#define ISL7998x_REG_P5_ONE_FIELD_MODE_CTL ISL7998x_REG(5, 0x09)
> +#define ISL7998x_REG_P5_MIPI_INT_HW_TST_CTR ISL7998x_REG(5, 0x0a)
> +#define ISL7998x_REG_P5_TP_GEN_BAR_PATTERN ISL7998x_REG(5, 0x0b)
> +#define ISL7998x_REG_P5_MIPI_PCNT_PSFRM ISL7998x_REG(5, 0x0c)
> +#define ISL7998x_REG_P5_LI_ENGINE_TP_GEN_CTL ISL7998x_REG(5, 0x0d)
> +#define ISL7998x_REG_P5_MIPI_VBLANK_PSFRM ISL7998x_REG(5, 0x0e)
> +#define ISL7998x_REG_P5_LI_ENGINE_CTL_2 ISL7998x_REG(5, 0x0f)
> +#define ISL7998x_REG_P5_MIPI_WCNT_1 ISL7998x_REG(5, 0x10)
> +#define ISL7998x_REG_P5_MIPI_WCNT_2 ISL7998x_REG(5, 0x11)
> +#define ISL7998x_REG_P5_MIPI_DPHY_TIMING_CTL_1 ISL7998x_REG(5, 0x12)
> +#define ISL7998x_REG_P5_MIPI_DPHY_TIMING_CTL_2 ISL7998x_REG(5, 0x13)
> +#define ISL7998x_REG_P5_MIPI_DPHY_TIMING_CTL_3 ISL7998x_REG(5, 0x14)
> +#define ISL7998x_REG_P5_MIPI_DPHY_TIMING_CTL_4 ISL7998x_REG(5, 0x15)
> +#define ISL7998x_REG_P5_MIPI_DPHY_TIMING_CTL_5 ISL7998x_REG(5, 0x16)
> +#define ISL7998x_REG_P5_MIPI_DPHY_TIMING_CTL_6 ISL7998x_REG(5, 0x17)
> +#define ISL7998x_REG_P5_MIPI_DPHY_PARAMS_1 ISL7998x_REG(5, 0x18)
> +#define ISL7998x_REG_P5_MIPI_DPHY_SOT_PERIOD ISL7998x_REG(5, 0x19)
> +#define ISL7998x_REG_P5_MIPI_DPHY_EOT_PERIOD ISL7998x_REG(5, 0x1a)
> +#define ISL7998x_REG_P5_MIPI_DPHY_PARAMS_2 ISL7998x_REG(5, 0x1b)
> +#define ISL7998x_REG_P5_MIPI_DPHY_TIMING_CTL_7 ISL7998x_REG(5, 0x1c)
> +#define ISL7998x_REG_P5_MIPI_DPHY_TIMING_CTL_8 ISL7998x_REG(5, 0x1d)
> +#define ISL7998x_REG_P5_MIPI_DPHY_TIMING_CTL_9 ISL7998x_REG(5, 0x1e)
> +#define ISL7998x_REG_P5_MIPI_DPHY_TIMING_CTL_10 ISL7998x_REG(5, 0x1f)
> +#define ISL7998x_REG_P5_TP_GEN_MIPI ISL7998x_REG(5, 0x20)
> +#define ISL7998x_REG_P5_ESC_MODE_TIME_CTL ISL7998x_REG(5, 0x21)
> +#define ISL7998x_REG_P5_AUTO_TEST_ERR_DET ISL7998x_REG(5, 0x22)
> +#define ISL7998x_REG_P5_MIPI_TIMING ISL7998x_REG(5, 0x23)
> +#define ISL7998x_REG_P5_PIC_HEIGHT_HIGH ISL7998x_REG(5, 0x24)
> +#define ISL7998x_REG_P5_PIC_HEIGHT_LOW ISL7998x_REG(5, 0x25)
> +#define ISL7998x_REG_P5_MIPI_SP_HS_TRL_CTL ISL7998x_REG(5, 0x26)
> +#define ISL7998x_REG_P5_FIFO_THRSH_CNT_1 ISL7998x_REG(5, 0x28)
> +#define ISL7998x_REG_P5_FIFO_THRSH_CNT_2 ISL7998x_REG(5, 0x29)
> +#define ISL7998x_REG_P5_TP_GEN_RND_SYNC_CTL_1 ISL7998x_REG(5, 0x2a)
> +#define ISL7998x_REG_P5_TP_GEN_RND_SYNC_CTL_2 ISL7998x_REG(5, 0x2b)
> +#define ISL7998x_REG_P5_PSF_FIELD_END_CTL_1 ISL7998x_REG(5, 0x2c)
> +#define ISL7998x_REG_P5_PSF_FIELD_END_CTL_2 ISL7998x_REG(5, 0x2d)
> +#define ISL7998x_REG_P5_PSF_FIELD_END_CTL_3 ISL7998x_REG(5, 0x2e)
> +#define ISL7998x_REG_P5_PSF_FIELD_END_CTL_4 ISL7998x_REG(5, 0x2f)
> +#define ISL7998x_REG_P5_MIPI_ANA_DATA_CTL_1 ISL7998x_REG(5, 0x30)
> +#define ISL7998x_REG_P5_MIPI_ANA_DATA_CTL_2 ISL7998x_REG(5, 0x31)
> +#define ISL7998x_REG_P5_MIPI_ANA_CLK_CTL ISL7998x_REG(5, 0x32)
> +#define ISL7998x_REG_P5_PLL_ANA_STATUS ISL7998x_REG(5, 0x33)
> +#define ISL7998x_REG_P5_PLL_ANA_MISC_CTL ISL7998x_REG(5, 0x34)
> +#define ISL7998x_REG_P5_MIPI_ANA ISL7998x_REG(5, 0x35)
> +#define ISL7998x_REG_P5_PLL_ANA ISL7998x_REG(5, 0x36)
> +#define ISL7998x_REG_P5_TOTAL_PF_LINE_CNT_1 ISL7998x_REG(5, 0x38)
> +#define ISL7998x_REG_P5_TOTAL_PF_LINE_CNT_2 ISL7998x_REG(5, 0x39)
> +#define ISL7998x_REG_P5_H_LINE_CNT_1 ISL7998x_REG(5, 0x3a)
> +#define ISL7998x_REG_P5_H_LINE_CNT_2 ISL7998x_REG(5, 0x3b)
> +#define ISL7998x_REG_P5_HIST_LINE_CNT_1 ISL7998x_REG(5, 0x3c)
> +#define ISL7998x_REG_P5_HIST_LINE_CNT_2 ISL7998x_REG(5, 0x3d)
> +
> +static const struct reg_sequence isl7998x_init_seq_1[] = {
> + { ISL7998x_REG_P0_SHORT_DIAG_IRQ_EN, 0xff },
> + { ISL7998x_REG_Px_DEC_SDT(0x1), 0x07 },
> + { ISL7998x_REG_Px_DEC_SHORT_DET_CTL_1(0x1), 0x03 },
> + { ISL7998x_REG_Px_DEC_SDT(0x2), 0x07 },
> + { ISL7998x_REG_Px_DEC_SHORT_DET_CTL_1(0x2), 0x03 },
> + { ISL7998x_REG_Px_DEC_SDT(0x3), 0x07 },
> + { ISL7998x_REG_Px_DEC_SHORT_DET_CTL_1(0x3), 0x03 },
> + { ISL7998x_REG_Px_DEC_SDT(0x4), 0x07 },
> + { ISL7998x_REG_Px_DEC_SHORT_DET_CTL_1(0x4), 0x03 },
> + { ISL7998x_REG_P5_LI_ENGINE_CTL, 0x00 },
> + { ISL7998x_REG_P0_SW_RESET_CTL, 0x1f, 10 },
> + { ISL7998x_REG_P0_IO_BUFFER_CTL, 0x00 },
> + { ISL7998x_REG_P0_MPP2_SYNC_CTL, 0xc9 },
> + { ISL7998x_REG_P0_IRQ_SYNC_CTL, 0xc9 },
> + { ISL7998x_REG_P0_CHAN_1_IRQ, 0x03 },
> + { ISL7998x_REG_P0_CHAN_2_IRQ, 0x00 },
> + { ISL7998x_REG_P0_CHAN_3_IRQ, 0x00 },
> + { ISL7998x_REG_P0_CHAN_4_IRQ, 0x00 },
> + { ISL7998x_REG_P5_LI_ENGINE_CTL, 0x02 },
> + { ISL7998x_REG_P5_LI_ENGINE_LINE_CTL, 0x85 },
> + { ISL7998x_REG_P5_LI_ENGINE_PIC_WIDTH, 0xa0 },
> + { ISL7998x_REG_P5_LI_ENGINE_SYNC_CTL, 0x18 },
> + { ISL7998x_REG_P5_LI_ENGINE_TYPE_CTL, 0x40 },
> + { ISL7998x_REG_P5_LI_ENGINE_FIFO_CTL, 0x40 },
> + { ISL7998x_REG_P5_MIPI_WCNT_1, 0x05 },
> + { ISL7998x_REG_P5_MIPI_WCNT_2, 0xa0 },
> + { ISL7998x_REG_P5_TP_GEN_MIPI, 0x00 },
> + { ISL7998x_REG_P5_ESC_MODE_TIME_CTL, 0x0c },
> + { ISL7998x_REG_P5_MIPI_SP_HS_TRL_CTL, 0x00 },
> + { ISL7998x_REG_P5_TP_GEN_RND_SYNC_CTL_1, 0x00 },
> + { ISL7998x_REG_P5_TP_GEN_RND_SYNC_CTL_2, 0x19 },
> + { ISL7998x_REG_P5_PSF_FIELD_END_CTL_1, 0x18 },
> + { ISL7998x_REG_P5_PSF_FIELD_END_CTL_2, 0xf1 },
> + { ISL7998x_REG_P5_PSF_FIELD_END_CTL_3, 0x00 },
> + { ISL7998x_REG_P5_PSF_FIELD_END_CTL_4, 0xf1 },
> + { ISL7998x_REG_P5_MIPI_ANA_DATA_CTL_1, 0x00 },
> + { ISL7998x_REG_P5_MIPI_ANA_DATA_CTL_2, 0x00 },
> + { ISL7998x_REG_P5_MIPI_ANA_CLK_CTL, 0x00 },
> + { ISL7998x_REG_P5_PLL_ANA_STATUS, 0xc0 },
> + { ISL7998x_REG_P5_PLL_ANA_MISC_CTL, 0x18 },
> + { ISL7998x_REG_P5_PLL_ANA, 0x00 },
> + { ISL7998x_REG_P0_SW_RESET_CTL, 0x10, 10 },
> + /* Page 0xf means write to all of pages 1,2,3,4 */
> + { ISL7998x_REG_Px_DEC_VDELAY_LO(0xf), 0x14 },
> + { ISL7998x_REG_Px_DEC_MISC3(0xf), 0xe6 },
> + { ISL7998x_REG_Px_DEC_CLMD(0xf), 0x85 },
> + { ISL7998x_REG_Px_DEC_H_DELAY_II_LOW(0xf), 0x11 },
> + { ISL7998x_REG_Px_ACA_XFER_HIST_HOST(0xf), 0x00 },
> + { ISL7998x_REG_P0_CLK_CTL_1, 0x1f },
> + { ISL7998x_REG_P0_CLK_CTL_2, 0x43 },
> + { ISL7998x_REG_P0_CLK_CTL_3, 0x4f },
It'd be great to see what these magical numbers signify. How about some
additional #defines for the bits? Same below.
> +};
> +
> +static const struct reg_sequence isl7998x_init_seq_2[] = {
> + { ISL7998x_REG_P5_LI_ENGINE_SYNC_CTL, 0x10 },
> + { ISL7998x_REG_P5_LI_ENGINE_VC_ASSIGNMENT, 0xe4 },
> + { ISL7998x_REG_P5_LI_ENGINE_TYPE_CTL, 0x00 },
> + { ISL7998x_REG_P5_LI_ENGINE_FIFO_CTL, 0x60 },
> + { ISL7998x_REG_P5_MIPI_READ_START_CTL, 0x2b },
> + { ISL7998x_REG_P5_PSEUDO_FRM_FIELD_CTL, 0x02 },
> + { ISL7998x_REG_P5_ONE_FIELD_MODE_CTL, 0x00 },
> + { ISL7998x_REG_P5_MIPI_INT_HW_TST_CTR, 0x62 },
> + { ISL7998x_REG_P5_TP_GEN_BAR_PATTERN, 0x02 },
> + { ISL7998x_REG_P5_MIPI_PCNT_PSFRM, 0x36 },
> + { ISL7998x_REG_P5_LI_ENGINE_TP_GEN_CTL, 0x00 },
> + { ISL7998x_REG_P5_MIPI_VBLANK_PSFRM, 0x6c },
> + { ISL7998x_REG_P5_LI_ENGINE_CTL_2, 0x00 },
> + { ISL7998x_REG_P5_MIPI_WCNT_1, 0x05 },
> + { ISL7998x_REG_P5_MIPI_WCNT_2, 0xa0 },
> + { ISL7998x_REG_P5_MIPI_DPHY_TIMING_CTL_1, 0x77 },
> + { ISL7998x_REG_P5_MIPI_DPHY_TIMING_CTL_2, 0x17 },
> + { ISL7998x_REG_P5_MIPI_DPHY_TIMING_CTL_3, 0x08 },
> + { ISL7998x_REG_P5_MIPI_DPHY_TIMING_CTL_4, 0x38 },
> + { ISL7998x_REG_P5_MIPI_DPHY_TIMING_CTL_5, 0x14 },
> + { ISL7998x_REG_P5_MIPI_DPHY_TIMING_CTL_6, 0xf6 },
> + { ISL7998x_REG_P5_MIPI_DPHY_PARAMS_1, 0x00 },
> + { ISL7998x_REG_P5_MIPI_DPHY_SOT_PERIOD, 0x17 },
> + { ISL7998x_REG_P5_MIPI_DPHY_EOT_PERIOD, 0x0a },
> + { ISL7998x_REG_P5_MIPI_DPHY_PARAMS_2, 0x71 },
> + { ISL7998x_REG_P5_MIPI_DPHY_TIMING_CTL_7, 0x7a },
> + { ISL7998x_REG_P5_MIPI_DPHY_TIMING_CTL_8, 0x0f },
> + { ISL7998x_REG_P5_MIPI_DPHY_TIMING_CTL_9, 0x8c },
> + { ISL7998x_REG_P5_MIPI_SP_HS_TRL_CTL, 0x08 },
> + { ISL7998x_REG_P5_FIFO_THRSH_CNT_1, 0x01 },
> + { ISL7998x_REG_P5_FIFO_THRSH_CNT_2, 0x0e },
> + { ISL7998x_REG_P5_TP_GEN_RND_SYNC_CTL_1, 0x00 },
> + { ISL7998x_REG_P5_TP_GEN_RND_SYNC_CTL_2, 0x00 },
> + { ISL7998x_REG_P5_TOTAL_PF_LINE_CNT_1, 0x03 },
> + { ISL7998x_REG_P5_TOTAL_PF_LINE_CNT_2, 0xc0 },
> + { ISL7998x_REG_P5_H_LINE_CNT_1, 0x06 },
> + { ISL7998x_REG_P5_H_LINE_CNT_2, 0xb3 },
> + { ISL7998x_REG_P5_HIST_LINE_CNT_1, 0x00 },
> + { ISL7998x_REG_P5_HIST_LINE_CNT_2, 0xf1 },
> + { ISL7998x_REG_P5_LI_ENGINE_FIFO_CTL, 0x00 },
> + { ISL7998x_REG_P5_MIPI_ANA, 0x00 },
> + /*
> + * Wait a bit after reset so that the chip can capture a frame
> + * and update internal line counters.
> + */
> + { ISL7998x_REG_P0_SW_RESET_CTL, 0x00, 50 },
> +};
> +
> +struct isl7998x_datafmt {
> + u32 code;
> + enum v4l2_colorspace colorspace;
> +};
> +
> +static const struct isl7998x_datafmt isl7998x_colour_fmts[] = {
> + { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_SRGB },
> +};
> +
> +/* Menu items for LINK_FREQ V4L2 control */
> +static const s64 link_freq_menu_items[] = {
> + 108000000, 216000000, 432000000
> +};
Where to these numbers come from?
> +
> +/* Menu items for TEST_PATTERN V4L2 control */
> +static const char * const isl7998x_test_pattern_menu[] = {
> + "Disabled", "Enabled-PAL (720x576)", "Enabled-NTSC (720x480)"
> +};
> +
> +struct isl7998x {
> + struct v4l2_subdev subdev;
> + struct regmap *regmap;
> + struct gpio_desc *pd_gpio;
> + unsigned int nr_mipi_lanes;
> + u32 nr_inputs;
> +
> + unsigned int width;
> + unsigned int height;
> + const struct isl7998x_datafmt *fmt;
> +#ifdef CONFIG_MEDIA_CONTROLLER
> + struct media_pad pad;
Hmm. Didn't you have four inputs in your device?
> +#endif
> +
> + struct v4l2_ctrl_handler ctrl_handler;
> + struct mutex ctrl_mutex;
> + /* V4L2 Controls */
> + struct v4l2_ctrl *link_freq;
> + u8 test_pattern_enabled;
> + u8 test_pattern_bars;
> + u8 test_pattern_chans;
> + u8 test_pattern_color;
> +};
> +
> +static struct isl7998x *sd_to_isl7998x(struct v4l2_subdev *sd)
> +{
> + return container_of(sd, struct isl7998x, subdev);
> +}
> +
> +static struct isl7998x *i2c_to_isl7998x(const struct i2c_client *client)
> +{
> + return sd_to_isl7998x(i2c_get_clientdata(client));
> +}
> +
> +static int isl7998x_init(struct isl7998x *isl7998x)
> +{
> + const unsigned int lanes = isl7998x->nr_mipi_lanes;
> + const u32 isl7998x_video_in_chan_map[] = { 0x00, 0x11, 0x02, 0x02 };
> + const struct reg_sequence isl7998x_init_seq_custom[] = {
> + { ISL7998x_REG_P0_VIDEO_IN_CHAN_CTL,
> + isl7998x_video_in_chan_map[isl7998x->nr_inputs - 1] },
> + { ISL7998x_REG_P0_CLK_CTL_4, (lanes == 1) ? 0x40 : 0x41 },
> + { ISL7998x_REG_P5_LI_ENGINE_CTL, (lanes == 1) ? 0x01 : 0x02 },
> + { ISL7998x_REG_P5_LI_ENGINE_LINE_CTL,
> + 0x20 | ((isl7998x->width >> 7) & 0x1f) },
> + { ISL7998x_REG_P5_LI_ENGINE_PIC_WIDTH,
> + (isl7998x->width << 1) & 0xff },
> + };
> + struct regmap *regmap = isl7998x->regmap;
> + int ret;
> +
> + ret = regmap_register_patch(regmap, isl7998x_init_seq_1,
> + ARRAY_SIZE(isl7998x_init_seq_1));
> + if (ret)
> + return ret;
> +
> + ret = regmap_register_patch(regmap, isl7998x_init_seq_custom,
> + ARRAY_SIZE(isl7998x_init_seq_custom));
> + if (ret)
> + return ret;
> +
> + return regmap_register_patch(regmap, isl7998x_init_seq_2,
> + ARRAY_SIZE(isl7998x_init_seq_2));
> +}
> +
> +static int isl7998x_g_mbus_config(struct v4l2_subdev *sd,
> + struct v4l2_mbus_config *cfg)
> +{
> + struct isl7998x *isl7998x = sd_to_isl7998x(sd);
> +
> + cfg->type = V4L2_MBUS_CSI2_DPHY;
> + cfg->flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
> + if (isl7998x->nr_mipi_lanes == 1)
> + cfg->flags |= V4L2_MBUS_CSI2_1_LANE;
> + else
> + cfg->flags |= V4L2_MBUS_CSI2_2_LANE;
Drivers nowadays generally get this from DT. You can omit this function
safely. For dynamic configuration we'll need something else (Jacopo's been
working on that with me).
> +
> + return 0;
> +}
> +
> +static int isl7998x_s_stream(struct v4l2_subdev *sd, int enable)
> +{
> + struct isl7998x *isl7998x = sd_to_isl7998x(sd);
> +
> + return isl7998x_init(isl7998x);
Is this needed both to initialise the hardware as well as start streaming?
Does this also enable the CSI-2 transmitter in driver's probe? This could
be problematic for some receivers.
> +}
> +
> +static int isl7998x_enum_mbus_code(struct v4l2_subdev *sd,
> + struct v4l2_subdev_pad_config *cfg,
> + struct v4l2_subdev_mbus_code_enum *code)
> +{
> + if (code->pad || code->index >= ARRAY_SIZE(isl7998x_colour_fmts))
> + return -EINVAL;
> +
> + code->code = isl7998x_colour_fmts[code->index].code;
A newline would be nice here.
> + return 0;
> +}
> +
> +static const unsigned int isl7998x_std_res[] = {
> + 480, 576, 576, 480, 480, 576, 480, 480
> +};
> +
> +static int isl7998x_update_std(struct isl7998x *isl7998x)
> +{
> + unsigned int height[ISL7998x_INPUTS];
> + u8 scanning = GENMASK(ISL7998x_INPUTS - 1, 0);
> + unsigned int i;
> + int ret;
> + u32 reg;
> +
> + while (true) {
> + for (i = 0; i < ISL7998x_INPUTS; i++) {
> + ret = regmap_read(isl7998x->regmap,
> + ISL7998x_REG_Px_DEC_SDT(i + 1), ®);
> + if (ret)
> + return ret;
> +
> + /* Detection is still in progress, restart. */
> + if (reg & ISL7998x_REG_Px_DEC_SDT_DET) {
> + scanning = GENMASK(ISL7998x_INPUTS - 1, 0);
> + break;
> + }
> +
> + scanning &= ~BIT(i);
> + height[i] = isl7998x_std_res[(reg >> 4) & 0x7];
> + }
> +
> + if (!scanning)
> + break;
> +
> + mdelay(1);
How long does this take in general? Could you use msleep() instead of
mdelay() in order to avoid a busy loop at least seemingly of unknown
length?
> + }
> +
> + /*
> + * According to Renesas FAE, all input cameras must have the
> + * same standard on this chip.
> + */
> + for (i = 1; i < isl7998x->nr_inputs ; i++)
> + if (height[i - 1] != height[i])
> + return -EINVAL;
> +
> + isl7998x->height = height[0];
> +
> + return 0;
> +}
> +
> +static int isl7998x_get_fmt(struct v4l2_subdev *sd,
> + struct v4l2_subdev_pad_config *cfg,
> + struct v4l2_subdev_format *format)
> +{
> + struct isl7998x *isl7998x = sd_to_isl7998x(sd);
> + struct v4l2_mbus_framefmt *mf = &format->format;
> +
> + if (format->pad != 0)
> + return -EINVAL;
> +
> + if (isl7998x->test_pattern_enabled == 1) {
> + mf->width = 720;
> + mf->height = 576;
> + } else if (isl7998x->test_pattern_enabled == 2) {
> + mf->width = 720;
> + mf->height = 480;
> + } else {
> + mf->width = isl7998x->width;
> + mf->height = isl7998x->height;
> + }
> +
> + mf->code = isl7998x->fmt->code;
> + mf->field = V4L2_FIELD_INTERLACED;
> + mf->colorspace = 0;
> +
> + return 0;
> +}
> +
> +static int isl7998x_set_fmt(struct v4l2_subdev *sd,
> + struct v4l2_subdev_pad_config *cfg,
> + struct v4l2_subdev_format *format)
> +{
> + struct isl7998x *isl7998x = sd_to_isl7998x(sd);
> + struct v4l2_mbus_framefmt *mf = &format->format;
> + int ret;
> +
> + if (format->pad != 0)
> + return -EINVAL;
You can omit the pad checks in pad ops; the framework does that nowadays.
> +
> + if (format->format.width != 720 ||
> + (format->format.height != 480 && format->format.height != 576))
> + return -EINVAL;
> +
> + if (format->format.code != MEDIA_BUS_FMT_YUYV8_2X8)
> + return -EINVAL;
Instead of returning an error, you should simply pick a valid format if the
user-supplied format (mbus code, size) isn't supported.
> +
> + mf->width = format->format.width;
> + mf->height = format->format.height;
> + mf->code = format->format.code;
> + mf->field = V4L2_FIELD_INTERLACED;
> + mf->colorspace = 0;
I'd just use what the user provided.
> +
> + if (format->which != V4L2_SUBDEV_FORMAT_TRY) {
> + ret = isl7998x_update_std(isl7998x);
> + if (ret)
> + return ret;
> + mf->width = isl7998x->width;
> + mf->height = isl7998x->height;
> + isl7998x->fmt = &isl7998x_colour_fmts[0];
> + }
> +
> + return 0;
> +}
> +
> +static int isl7998x_set_test_pattern(struct isl7998x *isl7998x)
> +{
> + const struct reg_sequence isl7998x_init_seq_tpg_off[] = {
> + { ISL7998x_REG_P5_LI_ENGINE_TP_GEN_CTL, 0 },
> + { ISL7998x_REG_P5_LI_ENGINE_CTL_2, 0 }
> + };
> + const struct reg_sequence isl7998x_init_seq_tpg_on[] = {
> + { ISL7998x_REG_P5_TP_GEN_BAR_PATTERN,
> + isl7998x->test_pattern_bars << 6 },
> + { ISL7998x_REG_P5_LI_ENGINE_CTL_2,
> + isl7998x->test_pattern_enabled == 1 ? BIT(2) : 0 },
> + { ISL7998x_REG_P5_LI_ENGINE_TP_GEN_CTL,
> + (isl7998x->test_pattern_chans << 4) |
> + (isl7998x->test_pattern_color << 2) }
> + };
> + struct regmap *regmap = isl7998x->regmap;
> +
> + if (isl7998x->test_pattern_enabled) {
> + return regmap_register_patch(regmap, isl7998x_init_seq_tpg_on,
> + ARRAY_SIZE(isl7998x_init_seq_tpg_on));
> + } else {
> + return regmap_register_patch(regmap, isl7998x_init_seq_tpg_off,
> + ARRAY_SIZE(isl7998x_init_seq_tpg_off));
> + }
No need for braces.
> +}
> +
> +static int isl7998x_set_ctrl(struct v4l2_ctrl *ctrl)
> +{
> + struct isl7998x *isl7998x = container_of(ctrl->handler,
> + struct isl7998x, ctrl_handler);
> +
> + switch (ctrl->id) {
> + case V4L2_CID_TEST_PATTERN_BARS:
> + isl7998x->test_pattern_bars = ctrl->val & 0x3;
> + return isl7998x_set_test_pattern(isl7998x);
> + case V4L2_CID_TEST_PATTERN_CHANNELS:
> + isl7998x->test_pattern_chans = ctrl->val & 0xf;
> + return isl7998x_set_test_pattern(isl7998x);
> + case V4L2_CID_TEST_PATTERN_COLOR:
> + isl7998x->test_pattern_color = ctrl->val & 0x3;
> + return isl7998x_set_test_pattern(isl7998x);
> + case V4L2_CID_TEST_PATTERN:
> + isl7998x->test_pattern_enabled = !!ctrl->val;
> + return isl7998x_set_test_pattern(isl7998x);
It'd simplify the driver to use the control value in
isl7998x_set_test_pattern() without storing the intermediate result in
driver's own struct.
> + }
> +
> + return 0;
> +}
> +
> +static int isl7998x_get_ctrl(struct v4l2_ctrl *ctrl)
> +{
> + struct isl7998x *isl7998x = container_of(ctrl->handler,
> + struct isl7998x, ctrl_handler);
> +
> + v4l2_info(&isl7998x->subdev, "ctrl(id:0x%x,val:0x%x) is not handled\n",
> + ctrl->id, ctrl->val);
If you have no volatile controls, you can omit this function.
> +
> + return 0;
> +}
> +
> +static const struct v4l2_subdev_video_ops isl7998x_subdev_video_ops = {
> + .g_mbus_config = isl7998x_g_mbus_config,
> + .s_stream = isl7998x_s_stream,
> +};
> +
> +static const struct v4l2_subdev_pad_ops isl7998x_subdev_pad_ops = {
> + .enum_mbus_code = isl7998x_enum_mbus_code,
> + .get_fmt = isl7998x_get_fmt,
> + .set_fmt = isl7998x_set_fmt,
> +};
> +
> +static const struct v4l2_subdev_ops isl7998x_subdev_ops = {
> + .video = &isl7998x_subdev_video_ops,
> + .pad = &isl7998x_subdev_pad_ops,
> +};
> +
> +static const struct media_entity_operations isl7998x_entity_ops = {
> + .link_validate = v4l2_subdev_link_validate,
> +};
> +
> +static const struct v4l2_ctrl_ops isl7998x_ctrl_ops = {
> + .s_ctrl = isl7998x_set_ctrl,
> + .g_volatile_ctrl = isl7998x_get_ctrl,
> +};
> +
> +static const char * const isl7998x_test_pattern_bars[] = {
> + "bbbbwb", "bbbwwb", "bbwbwb", "bbwwwb"
> +};
> +
> +static const char * const isl7998x_test_pattern_colors[] = {
> + "Yellow", "Blue", "Green", "Pink"
> +};
> +
> +static const struct v4l2_ctrl_config isl7998x_ctrls[] = {
> + {
> + .ops = &isl7998x_ctrl_ops,
> + .id = V4L2_CID_TEST_PATTERN_BARS,
> + .type = V4L2_CTRL_TYPE_MENU,
> + .name = "Test Pattern Bars",
> + .max = ARRAY_SIZE(isl7998x_test_pattern_bars) - 1,
> + .def = 0,
> + .qmenu = isl7998x_test_pattern_bars,
> + }, {
> + .ops = &isl7998x_ctrl_ops,
> + .id = V4L2_CID_TEST_PATTERN_CHANNELS,
> + .type = V4L2_CTRL_TYPE_INTEGER,
> + .name = "Test Pattern Channels",
> + .min = 0,
> + .max = 0xf,
> + .step = 1,
> + .def = 0,
> + .flags = 0,
> + }, {
> + .ops = &isl7998x_ctrl_ops,
> + .id = V4L2_CID_TEST_PATTERN_COLOR,
> + .type = V4L2_CTRL_TYPE_MENU,
> + .name = "Test Pattern Color",
> + .max = ARRAY_SIZE(isl7998x_test_pattern_colors) - 1,
> + .def = 0,
> + .qmenu = isl7998x_test_pattern_colors,
> + },
> +};
> +
> +#define ISL7998x_REG_DECODER_ACA_READABLE_RANGE(page) \
> + /* Decoder range */ \
> + regmap_reg_range(ISL7998x_REG_Px_DEC_INPUT_FMT(page), \
> + ISL7998x_REG_Px_DEC_HS_DELAY_CTL(page)), \
> + regmap_reg_range(ISL7998x_REG_Px_DEC_ANCTL(page), \
> + ISL7998x_REG_Px_DEC_CSC_CTL(page)), \
> + regmap_reg_range(ISL7998x_REG_Px_DEC_BRIGHT(page), \
> + ISL7998x_REG_Px_DEC_HUE(page)), \
> + regmap_reg_range(ISL7998x_REG_Px_DEC_VERT_PEAK(page), \
> + ISL7998x_REG_Px_DEC_CORING(page)), \
> + regmap_reg_range(ISL7998x_REG_Px_DEC_SDT(page), \
> + ISL7998x_REG_Px_DEC_SDTR(page)), \
> + regmap_reg_range(ISL7998x_REG_Px_DEC_CLMPG(page), \
> + ISL7998x_REG_Px_DEC_DATA_CONV(page)), \
> + regmap_reg_range(ISL7998x_REG_Px_DEC_INTERNAL_TEST(page), \
> + ISL7998x_REG_Px_DEC_INTERNAL_TEST(page)), \
> + regmap_reg_range(ISL7998x_REG_Px_DEC_H_DELAY_CTL(page), \
> + ISL7998x_REG_Px_DEC_H_DELAY_II_LOW(page)), \
> + /* ACA range */ \
> + regmap_reg_range(ISL7998x_REG_Px_ACA_CTL_1(page), \
> + ISL7998x_REG_Px_ACA_HIST_WIN_V_SZ2(page)), \
> + regmap_reg_range(ISL7998x_REG_Px_ACA_Y_AVG(page), \
> + ISL7998x_REG_Px_ACA_CTL_4(page)), \
> + regmap_reg_range(ISL7998x_REG_Px_ACA_FLEX_WIN_HIST(page), \
> + ISL7998x_REG_Px_ACA_XFER_HIST_HOST(page)), \
> + regmap_reg_range(ISL7998x_REG_Px_DEC_PAGE(page), \
> + ISL7998x_REG_Px_DEC_PAGE(page))
> +
> +#define ISL7998x_REG_DECODER_ACA_WRITEABLE_RANGE(page) \
> + /* Decoder range */ \
> + regmap_reg_range(ISL7998x_REG_Px_DEC_INPUT_FMT(page), \
> + ISL7998x_REG_Px_DEC_INPUT_FMT(page)), \
> + regmap_reg_range(ISL7998x_REG_Px_DEC_HS_DELAY_CTL(page), \
> + ISL7998x_REG_Px_DEC_HS_DELAY_CTL(page)), \
> + regmap_reg_range(ISL7998x_REG_Px_DEC_ANCTL(page), \
> + ISL7998x_REG_Px_DEC_CSC_CTL(page)), \
> + regmap_reg_range(ISL7998x_REG_Px_DEC_BRIGHT(page), \
> + ISL7998x_REG_Px_DEC_HUE(page)), \
> + regmap_reg_range(ISL7998x_REG_Px_DEC_VERT_PEAK(page), \
> + ISL7998x_REG_Px_DEC_CORING(page)), \
> + regmap_reg_range(ISL7998x_REG_Px_DEC_SDT(page), \
> + ISL7998x_REG_Px_DEC_SDTR(page)), \
> + regmap_reg_range(ISL7998x_REG_Px_DEC_CLMPG(page), \
> + ISL7998x_REG_Px_DEC_MISC3(page)), \
> + regmap_reg_range(ISL7998x_REG_Px_DEC_CLMD(page), \
> + ISL7998x_REG_Px_DEC_DATA_CONV(page)), \
> + regmap_reg_range(ISL7998x_REG_Px_DEC_INTERNAL_TEST(page), \
> + ISL7998x_REG_Px_DEC_INTERNAL_TEST(page)), \
> + regmap_reg_range(ISL7998x_REG_Px_DEC_H_DELAY_CTL(page), \
> + ISL7998x_REG_Px_DEC_H_DELAY_II_LOW(page)), \
> + /* ACA range */ \
> + regmap_reg_range(ISL7998x_REG_Px_ACA_CTL_1(page), \
> + ISL7998x_REG_Px_ACA_HIST_WIN_V_SZ2(page)), \
> + regmap_reg_range(ISL7998x_REG_Px_ACA_CTL_2(page), \
> + ISL7998x_REG_Px_ACA_CTL_4(page)), \
> + regmap_reg_range(ISL7998x_REG_Px_ACA_FLEX_WIN_HIST(page), \
> + ISL7998x_REG_Px_ACA_HIST_DATA_LO(page)), \
> + regmap_reg_range(ISL7998x_REG_Px_ACA_XFER_HIST_HOST(page), \
> + ISL7998x_REG_Px_ACA_XFER_HIST_HOST(page)), \
> + regmap_reg_range(ISL7998x_REG_Px_DEC_PAGE(page), \
> + ISL7998x_REG_Px_DEC_PAGE(page))
> +
> +#define ISL7998x_REG_DECODER_ACA_VOLATILE_RANGE(page) \
> + /* Decoder range */ \
> + regmap_reg_range(ISL7998x_REG_Px_DEC_STATUS_1(page), \
> + ISL7998x_REG_Px_DEC_STATUS_1(page)), \
> + regmap_reg_range(ISL7998x_REG_Px_DEC_SDT(page), \
> + ISL7998x_REG_Px_DEC_SDT(page)), \
> + regmap_reg_range(ISL7998x_REG_Px_DEC_MVSN(page), \
> + ISL7998x_REG_Px_DEC_HFREF(page)), \
> + /* ACA range */ \
> + regmap_reg_range(ISL7998x_REG_Px_ACA_Y_AVG(page), \
> + ISL7998x_REG_Px_ACA_Y_HIGH(page)), \
> + regmap_reg_range(ISL7998x_REG_Px_ACA_HIST_DATA_LO(page), \
> + ISL7998x_REG_Px_ACA_FLEX_WIN_CR_CLR(page))
> +
> +static const struct regmap_range isl7998x_readable_ranges[] = {
> + regmap_reg_range(ISL7998x_REG_P0_PRODUCT_ID_CODE,
> + ISL7998x_REG_P0_IRQ_SYNC_CTL),
> + regmap_reg_range(ISL7998x_REG_P0_INTERRUPT_STATUS,
> + ISL7998x_REG_P0_CLOCK_DELAY),
> + regmap_reg_range(ISL7998x_REG_Px_DEC_PAGE(0),
> + ISL7998x_REG_Px_DEC_PAGE(0)),
> +
> + ISL7998x_REG_DECODER_ACA_READABLE_RANGE(1),
> + ISL7998x_REG_DECODER_ACA_READABLE_RANGE(2),
> + ISL7998x_REG_DECODER_ACA_READABLE_RANGE(3),
> + ISL7998x_REG_DECODER_ACA_READABLE_RANGE(4),
> +
> + regmap_reg_range(ISL7998x_REG_P5_LI_ENGINE_CTL,
> + ISL7998x_REG_P5_MIPI_SP_HS_TRL_CTL),
> + regmap_reg_range(ISL7998x_REG_P5_FIFO_THRSH_CNT_1,
> + ISL7998x_REG_P5_PLL_ANA),
> + regmap_reg_range(ISL7998x_REG_P5_TOTAL_PF_LINE_CNT_1,
> + ISL7998x_REG_P5_HIST_LINE_CNT_2),
> + regmap_reg_range(ISL7998x_REG_Px_DEC_PAGE(5),
> + ISL7998x_REG_Px_DEC_PAGE(5)),
> +};
> +
> +static const struct regmap_range isl7998x_writeable_ranges[] = {
> + regmap_reg_range(ISL7998x_REG_P0_SW_RESET_CTL,
> + ISL7998x_REG_P0_IRQ_SYNC_CTL),
> + regmap_reg_range(ISL7998x_REG_P0_CHAN_1_IRQ,
> + ISL7998x_REG_P0_SHORT_DIAG_IRQ_EN),
> + regmap_reg_range(ISL7998x_REG_P0_CLOCK_DELAY,
> + ISL7998x_REG_P0_CLOCK_DELAY),
> + regmap_reg_range(ISL7998x_REG_Px_DEC_PAGE(0),
> + ISL7998x_REG_Px_DEC_PAGE(0)),
> +
> + ISL7998x_REG_DECODER_ACA_WRITEABLE_RANGE(1),
> + ISL7998x_REG_DECODER_ACA_WRITEABLE_RANGE(2),
> + ISL7998x_REG_DECODER_ACA_WRITEABLE_RANGE(3),
> + ISL7998x_REG_DECODER_ACA_WRITEABLE_RANGE(4),
> +
> + regmap_reg_range(ISL7998x_REG_P5_LI_ENGINE_CTL,
> + ISL7998x_REG_P5_ESC_MODE_TIME_CTL),
> + regmap_reg_range(ISL7998x_REG_P5_MIPI_SP_HS_TRL_CTL,
> + ISL7998x_REG_P5_PLL_ANA),
> + regmap_reg_range(ISL7998x_REG_P5_TOTAL_PF_LINE_CNT_1,
> + ISL7998x_REG_P5_HIST_LINE_CNT_2),
> + regmap_reg_range(ISL7998x_REG_Px_DEC_PAGE(5),
> + ISL7998x_REG_Px_DEC_PAGE(5)),
> +
> + ISL7998x_REG_DECODER_ACA_WRITEABLE_RANGE(0xf),
> +};
> +
> +static const struct regmap_range isl7998x_volatile_ranges[] = {
> + regmap_reg_range(ISL7998x_REG_P0_MPP1_SYNC_CTL,
> + ISL7998x_REG_P0_IRQ_SYNC_CTL),
> + regmap_reg_range(ISL7998x_REG_P0_INTERRUPT_STATUS,
> + ISL7998x_REG_P0_INTERRUPT_STATUS),
> + regmap_reg_range(ISL7998x_REG_P0_CHAN_1_STATUS,
> + ISL7998x_REG_P0_SHORT_DIAG_STATUS),
> +
> + ISL7998x_REG_DECODER_ACA_VOLATILE_RANGE(1),
> + ISL7998x_REG_DECODER_ACA_VOLATILE_RANGE(2),
> + ISL7998x_REG_DECODER_ACA_VOLATILE_RANGE(3),
> + ISL7998x_REG_DECODER_ACA_VOLATILE_RANGE(4),
> +
> + regmap_reg_range(ISL7998x_REG_P5_AUTO_TEST_ERR_DET,
> + ISL7998x_REG_P5_PIC_HEIGHT_LOW),
> +};
> +
> +static const struct regmap_access_table isl7998x_readable_table = {
> + .yes_ranges = isl7998x_readable_ranges,
> + .n_yes_ranges = ARRAY_SIZE(isl7998x_readable_ranges),
> +};
> +
> +static const struct regmap_access_table isl7998x_writeable_table = {
> + .yes_ranges = isl7998x_writeable_ranges,
> + .n_yes_ranges = ARRAY_SIZE(isl7998x_writeable_ranges),
> +};
> +
> +static const struct regmap_access_table isl7998x_volatile_table = {
> + .yes_ranges = isl7998x_volatile_ranges,
> + .n_yes_ranges = ARRAY_SIZE(isl7998x_volatile_ranges),
> +};
> +
> +static const struct regmap_range_cfg isl7998x_ranges[] = {
> + {
> + .range_min = ISL7998x_REG_Pn_BASE(0),
> + .range_max = ISL7998x_REG_Px_ACA_XFER_HIST_HOST(0xf),
> + .selector_reg = ISL7998x_REG_Px_DEC_PAGE(0),
> + .selector_mask = ISL7998x_REG_Px_DEC_PAGE_MASK,
> + .window_start = 0,
> + .window_len = 256,
> + }
> +};
> +
> +static const struct regmap_config isl7998x_regmap = {
> + .reg_bits = 8,
> + .val_bits = 8,
> + .max_register = ISL7998x_REG_Px_ACA_XFER_HIST_HOST(0xf),
> + .ranges = isl7998x_ranges,
> + .num_ranges = ARRAY_SIZE(isl7998x_ranges),
> + .rd_table = &isl7998x_readable_table,
> + .wr_table = &isl7998x_writeable_table,
> + .volatile_table = &isl7998x_volatile_table,
> + .cache_type = REGCACHE_RBTREE,
> +};
> +
> +static int isl7998x_probe(struct i2c_client *client,
> + const struct i2c_device_id *did)
> +{
> + struct device *dev = &client->dev;
> + struct v4l2_fwnode_endpoint endpoint;
Please do initialise the bus_type field at least.
> + struct device_node *ep;
> + struct isl7998x *isl7998x;
> + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
> + u32 chip_id;
> + int i, ret;
> +
> + ret = i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA);
> + if (!ret) {
> + dev_warn(&adapter->dev,
> + "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
> + return -EIO;
> + }
> +
> + isl7998x = devm_kzalloc(dev, sizeof(*isl7998x), GFP_KERNEL);
> + if (!isl7998x)
> + return -ENOMEM;
> +
> + /* Default to all four inputs active unless specified otherwise. */
> + ret = of_property_read_u32(dev->of_node, "isil,num-inputs",
> + &isl7998x->nr_inputs);
> + if (ret)
> + isl7998x->nr_inputs = 4;
> +
> + if (isl7998x->nr_inputs != 1 && isl7998x->nr_inputs != 2 &&
> + isl7998x->nr_inputs != 4) {
> + dev_err(dev, "Invalid number of inputs selected in DT\n");
> + return -EINVAL;
> + }
> +
> + isl7998x->pd_gpio = devm_gpiod_get_optional(dev, "pd", GPIOD_OUT_HIGH);
> + if (IS_ERR(isl7998x->pd_gpio)) {
> + dev_err(dev, "Failed to retrieve/request PD GPIO: %ld\n",
> + PTR_ERR(isl7998x->pd_gpio));
> + return PTR_ERR(isl7998x->pd_gpio);
> + }
> +
> + isl7998x->regmap = devm_regmap_init_i2c(client, &isl7998x_regmap);
> + if (IS_ERR(isl7998x->regmap)) {
> + ret = PTR_ERR(isl7998x->regmap);
> + dev_err(dev, "Failed to allocate register map: %d\n", ret);
> + return ret;
> + }
> +
> + ep = of_graph_get_next_endpoint(dev->of_node, NULL);
> + if (!ep) {
> + dev_err(dev, "Missing endpoint node\n");
> + return -EINVAL;
> + }
> +
> + ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &endpoint);
> + of_node_put(ep);
> + if (ret) {
> + dev_err(dev, "Failed to parse endpoint\n");
> + return ret;
> + }
> +
> + if (endpoint.bus_type != V4L2_MBUS_CSI2_DPHY ||
> + endpoint.bus.mipi_csi2.num_data_lanes == 0 ||
> + endpoint.bus.mipi_csi2.num_data_lanes > 2) {
> + dev_err(dev, "Invalid bus type or number of MIPI lanes\n");
> + return -EINVAL;
> + }
> +
> + isl7998x->nr_mipi_lanes = endpoint.bus.mipi_csi2.num_data_lanes;
> +
> + v4l2_i2c_subdev_init(&isl7998x->subdev, client, &isl7998x_subdev_ops);
> + isl7998x->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
> +
> +#ifdef CONFIG_MEDIA_CONTROLLER
> + isl7998x->pad.flags = MEDIA_PAD_FL_SOURCE;
> + isl7998x->subdev.entity.ops = &isl7998x_entity_ops;
> + isl7998x->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR;
This is definitely not a camera sensor.
MEDIA_ENT_F_VID_IF_BRIDGE perhaps?
How does the driver work without MC? E.g. how are the formats on the inputs
set up?
> + ret = media_entity_pads_init(&isl7998x->subdev.entity, 1,
> + &isl7998x->pad);
> + if (ret < 0)
> + return ret;
> +#endif
> +
> + isl7998x->width = ISL7998x_WIDTH;
> + isl7998x->height = ISL7998x_HEIGHT;
> + isl7998x->fmt = &isl7998x_colour_fmts[0];
> +
> + ret = v4l2_ctrl_handler_init(&isl7998x->ctrl_handler,
> + 2 + ARRAY_SIZE(isl7998x_ctrls));
> + if (ret)
> + return ret;
> +
> + mutex_init(&isl7998x->ctrl_mutex);
> + isl7998x->ctrl_handler.lock = &isl7998x->ctrl_mutex;
> + isl7998x->link_freq = v4l2_ctrl_new_int_menu(&isl7998x->ctrl_handler,
> + &isl7998x_ctrl_ops, V4L2_CID_LINK_FREQ,
> + ARRAY_SIZE(link_freq_menu_items) - 1,
> + endpoint.bus.mipi_csi2.num_data_lanes == 2 ?
> + 1 : 0, link_freq_menu_items);
> + isl7998x->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
Note that v4l2_ctrl_new_int_menu() returns NULL on error. Please also check
the control handler's error status when you're done setting up controls,
and call v4l2_ctrl_handler_free() in cleanup if there was an error.
> +
> + for (i = 0; i < ARRAY_SIZE(isl7998x_ctrls); i++) {
> + v4l2_ctrl_new_custom(&isl7998x->ctrl_handler,
> + &isl7998x_ctrls[i], NULL);
> + }
No need for braces.
> +
> + v4l2_ctrl_new_std_menu_items(&isl7998x->ctrl_handler,
> + &isl7998x_ctrl_ops, V4L2_CID_TEST_PATTERN,
> + ARRAY_SIZE(isl7998x_test_pattern_menu) - 1,
> + 0, 0, isl7998x_test_pattern_menu);
> +
> + isl7998x->subdev.ctrl_handler = &isl7998x->ctrl_handler;
> +
> + isl7998x->subdev.dev = dev;
The dev field is initialised to the same value by v4l2_i2c_subdev_init().
Please remove.
> + ret = v4l2_async_register_subdev(&isl7998x->subdev);
> + if (ret < 0)
> + goto err_entity_cleanup;
> +
> + /*
> + * Turn the chip ON and keep it ON, otherwise the camera standard
> + * detection takes about 600 mS every time we do VIDIOC_G_FMT.
"ms". Unless you meant Siemens, a unit of conductance.
> + */
> + if (isl7998x->pd_gpio)
> + gpiod_set_value(isl7998x->pd_gpio, 0);
> +
> + ret = regmap_read(isl7998x->regmap, ISL7998x_REG_P0_PRODUCT_ID_CODE,
> + &chip_id);
> + if (ret) {
> + dev_err(dev, "Failed to read ID register: %d\n", ret);
> + goto err_init_cleanup;
> + }
> +
> + dev_info(dev, "ISL7998x found (id=%x)\n", chip_id);
> +
> + ret = isl7998x_init(isl7998x);
> + if (ret)
> + goto err_init_cleanup;
> +
> + ret = isl7998x_update_std(isl7998x);
> + if (ret)
> + goto err_init_cleanup;
> +
> + return 0;
> +
> +err_init_cleanup:
> + if (isl7998x->pd_gpio)
> + gpiod_set_value(isl7998x->pd_gpio, 1);
> +err_entity_cleanup:
> +#ifdef CONFIG_MEDIA_CONTROLLER
> + media_entity_cleanup(&isl7998x->subdev.entity);
> +#endif
You can remove the #ifdef here.
Newlines are nice before labels and return (unless it's right after if).
> + return ret;
> +}
> +
> +static int isl7998x_remove(struct i2c_client *client)
> +{
> + struct isl7998x *isl7998x = i2c_to_isl7998x(client);
> +
> + if (isl7998x->pd_gpio)
> + gpiod_set_value(isl7998x->pd_gpio, 1);
> + v4l2_async_unregister_subdev(&isl7998x->subdev);
> + v4l2_ctrl_handler_free(isl7998x->subdev.ctrl_handler);
> + media_entity_cleanup(&isl7998x->subdev.entity);
> +
> + return 0;
> +}
> +
> +static const struct of_device_id isl7998x_of_match[] = {
> + { .compatible = "isil,isl79987", },
> + {},
> +};
> +MODULE_DEVICE_TABLE(of, isl7998x_of_match);
> +
> +static const struct i2c_device_id isl7998x_id[] = {
> + { "isl79987", 0 },
> + { }
> +};
> +MODULE_DEVICE_TABLE(i2c, isl7998x_id);
> +
> +static struct i2c_driver isl7998x_i2c_driver = {
> + .driver = {
> + .name = "isl7998x",
> + .of_match_table = of_match_ptr(isl7998x_of_match),
> + },
> + .probe = isl7998x_probe,
> + .remove = isl7998x_remove,
> + .id_table = isl7998x_id,
Use probe_new, and you can omit the id_table.
> +};
> +
> +module_i2c_driver(isl7998x_i2c_driver);
> +
> +MODULE_DESCRIPTION("Intersil ISL7998x BT656-to-MIPI-CSI2 driver");
> +MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
> +MODULE_LICENSE("GPL");
The SPDX header indicates GPL v2.0. Which one is correct?
--
Kind regards,
Sakari Ailus
sakari.ailus@linux.intel.com
next prev parent reply other threads:[~2019-07-01 8:43 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-05-20 20:18 [PATCH 1/2] media: dt-bindings: Add Intersil ISL7998x DT bindings Marek Vasut
2019-05-20 20:18 ` [PATCH 2/2] media: i2c: isl7998x: Add driver for Intersil ISL7998x Marek Vasut
2019-07-01 7:58 ` Jacopo Mondi
2019-08-06 14:03 ` Marek Vasut
2019-08-12 15:39 ` Jacopo Mondi
2019-07-01 8:43 ` Sakari Ailus [this message]
2019-08-06 14:25 ` Marek Vasut
2019-07-01 8:46 ` Sakari Ailus
2019-05-28 11:47 ` [PATCH 1/2] media: dt-bindings: Add Intersil ISL7998x DT bindings Jacopo Mondi
2019-05-28 14:36 ` Marek Vasut
2019-05-28 15:10 ` Jacopo Mondi
2019-05-28 17:49 ` Marek Vasut
2019-05-29 6:28 ` Jacopo Mondi
2019-05-29 10:41 ` Marek Vasut
2019-05-29 11:04 ` Ian Arkver
2019-05-29 11:09 ` Marek Vasut
2019-05-29 11:15 ` Ian Arkver
2019-08-06 13:35 ` Marek Vasut
2019-05-29 13:43 ` Jacopo Mondi
2019-08-06 13:35 ` Marek Vasut
2019-07-01 8:04 ` Sakari Ailus
2019-08-06 13:35 ` Marek Vasut
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190701084315.eygyytirydies422@paasikivi.fi.intel.com \
--to=sakari.ailus@linux.intel.com \
--cc=linux-media@vger.kernel.org \
--cc=marex@denx.de \
--cc=mchehab+samsung@kernel.org \
--cc=robh+dt@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).