brintos

brintos / linux-shallow public Read only

0
0
Text · 54.4 KiB · 5ffd53e Raw
1627 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Intersil ISL7998x analog to MIPI CSI-2 or BT.656 decoder driver.4 *5 * Copyright (C) 2018-2019 Marek Vasut <marex@denx.de>6 * Copyright (C) 2021 Michael Tretter <kernel@pengutronix.de>7 */8 9#include <linux/bitfield.h>10#include <linux/delay.h>11#include <linux/gpio/consumer.h>12#include <linux/i2c.h>13#include <linux/module.h>14#include <linux/of_graph.h>15#include <linux/pm_runtime.h>16#include <linux/regmap.h>17#include <linux/slab.h>18#include <linux/v4l2-mediabus.h>19#include <linux/videodev2.h>20 21#include <media/v4l2-async.h>22#include <media/v4l2-common.h>23#include <media/v4l2-ctrls.h>24#include <media/v4l2-device.h>25#include <media/v4l2-fwnode.h>26#include <media/v4l2-ioctl.h>27 28/*29 * This control allows to activate and deactivate the test pattern on30 * selected output channels.31 * This value is ISL7998x specific.32 */33#define V4L2_CID_TEST_PATTERN_CHANNELS	(V4L2_CID_USER_ISL7998X_BASE + 0)34 35/*36 * This control allows to specify the color of the test pattern.37 * This value is ISL7998x specific.38 */39#define V4L2_CID_TEST_PATTERN_COLOR	(V4L2_CID_USER_ISL7998X_BASE + 1)40 41/*42 * This control allows to specify the bar pattern in the test pattern.43 * This value is ISL7998x specific.44 */45#define V4L2_CID_TEST_PATTERN_BARS	(V4L2_CID_USER_ISL7998X_BASE + 2)46 47#define ISL7998X_INPUTS			448 49#define ISL7998X_REG(page, reg)		(((page) << 8) | (reg))50 51#define ISL7998X_REG_PN_SIZE			25652#define ISL7998X_REG_PN_BASE(n)			((n) * ISL7998X_REG_PN_SIZE)53 54#define ISL7998X_REG_PX_DEC_PAGE(page)		ISL7998X_REG((page), 0xff)55#define ISL7998X_REG_PX_DEC_PAGE_MASK		0xf56#define ISL7998X_REG_P0_PRODUCT_ID_CODE		ISL7998X_REG(0, 0x00)57#define ISL7998X_REG_P0_PRODUCT_REV_CODE	ISL7998X_REG(0, 0x01)58#define ISL7998X_REG_P0_SW_RESET_CTL		ISL7998X_REG(0, 0x02)59#define ISL7998X_REG_P0_IO_BUFFER_CTL		ISL7998X_REG(0, 0x03)60#define ISL7998X_REG_P0_IO_BUFFER_CTL_1_1	ISL7998X_REG(0, 0x04)61#define ISL7998X_REG_P0_IO_PAD_PULL_EN_CTL	ISL7998X_REG(0, 0x05)62#define ISL7998X_REG_P0_IO_BUFFER_CTL_1_2	ISL7998X_REG(0, 0x06)63#define ISL7998X_REG_P0_VIDEO_IN_CHAN_CTL	ISL7998X_REG(0, 0x07)64#define ISL7998X_REG_P0_CLK_CTL_1		ISL7998X_REG(0, 0x08)65#define ISL7998X_REG_P0_CLK_CTL_2		ISL7998X_REG(0, 0x09)66#define ISL7998X_REG_P0_CLK_CTL_3		ISL7998X_REG(0, 0x0a)67#define ISL7998X_REG_P0_CLK_CTL_4		ISL7998X_REG(0, 0x0b)68#define ISL7998X_REG_P0_MPP1_SYNC_CTL		ISL7998X_REG(0, 0x0c)69#define ISL7998X_REG_P0_MPP2_SYNC_CTL		ISL7998X_REG(0, 0x0d)70#define ISL7998X_REG_P0_IRQ_SYNC_CTL		ISL7998X_REG(0, 0x0e)71#define ISL7998X_REG_P0_INTERRUPT_STATUS	ISL7998X_REG(0, 0x10)72#define ISL7998X_REG_P0_CHAN_1_IRQ		ISL7998X_REG(0, 0x11)73#define ISL7998X_REG_P0_CHAN_2_IRQ		ISL7998X_REG(0, 0x12)74#define ISL7998X_REG_P0_CHAN_3_IRQ		ISL7998X_REG(0, 0x13)75#define ISL7998X_REG_P0_CHAN_4_IRQ		ISL7998X_REG(0, 0x14)76#define ISL7998X_REG_P0_SHORT_DIAG_IRQ		ISL7998X_REG(0, 0x15)77#define ISL7998X_REG_P0_CHAN_1_IRQ_EN		ISL7998X_REG(0, 0x16)78#define ISL7998X_REG_P0_CHAN_2_IRQ_EN		ISL7998X_REG(0, 0x17)79#define ISL7998X_REG_P0_CHAN_3_IRQ_EN		ISL7998X_REG(0, 0x18)80#define ISL7998X_REG_P0_CHAN_4_IRQ_EN		ISL7998X_REG(0, 0x19)81#define ISL7998X_REG_P0_SHORT_DIAG_IRQ_EN	ISL7998X_REG(0, 0x1a)82#define ISL7998X_REG_P0_CHAN_1_STATUS		ISL7998X_REG(0, 0x1b)83#define ISL7998X_REG_P0_CHAN_2_STATUS		ISL7998X_REG(0, 0x1c)84#define ISL7998X_REG_P0_CHAN_3_STATUS		ISL7998X_REG(0, 0x1d)85#define ISL7998X_REG_P0_CHAN_4_STATUS		ISL7998X_REG(0, 0x1e)86#define ISL7998X_REG_P0_SHORT_DIAG_STATUS	ISL7998X_REG(0, 0x1f)87#define ISL7998X_REG_P0_CLOCK_DELAY		ISL7998X_REG(0, 0x20)88 89#define ISL7998X_REG_PX_DEC_INPUT_FMT(pg)	ISL7998X_REG((pg), 0x02)90#define ISL7998X_REG_PX_DEC_STATUS_1(pg)	ISL7998X_REG((pg), 0x03)91#define ISL7998X_REG_PX_DEC_STATUS_1_VDLOSS	BIT(7)92#define ISL7998X_REG_PX_DEC_STATUS_1_HLOCK	BIT(6)93#define ISL7998X_REG_PX_DEC_STATUS_1_VLOCK	BIT(3)94#define ISL7998X_REG_PX_DEC_HS_DELAY_CTL(pg)	ISL7998X_REG((pg), 0x04)95#define ISL7998X_REG_PX_DEC_ANCTL(pg)		ISL7998X_REG((pg), 0x06)96#define ISL7998X_REG_PX_DEC_CROP_HI(pg)		ISL7998X_REG((pg), 0x07)97#define ISL7998X_REG_PX_DEC_VDELAY_LO(pg)	ISL7998X_REG((pg), 0x08)98#define ISL7998X_REG_PX_DEC_VACTIVE_LO(pg)	ISL7998X_REG((pg), 0x09)99#define ISL7998X_REG_PX_DEC_HDELAY_LO(pg)	ISL7998X_REG((pg), 0x0a)100#define ISL7998X_REG_PX_DEC_HACTIVE_LO(pg)	ISL7998X_REG((pg), 0x0b)101#define ISL7998X_REG_PX_DEC_CNTRL1(pg)		ISL7998X_REG((pg), 0x0c)102#define ISL7998X_REG_PX_DEC_CSC_CTL(pg)		ISL7998X_REG((pg), 0x0d)103#define ISL7998X_REG_PX_DEC_BRIGHT(pg)		ISL7998X_REG((pg), 0x10)104#define ISL7998X_REG_PX_DEC_CONTRAST(pg)	ISL7998X_REG((pg), 0x11)105#define ISL7998X_REG_PX_DEC_SHARPNESS(pg)	ISL7998X_REG((pg), 0x12)106#define ISL7998X_REG_PX_DEC_SAT_U(pg)		ISL7998X_REG((pg), 0x13)107#define ISL7998X_REG_PX_DEC_SAT_V(pg)		ISL7998X_REG((pg), 0x14)108#define ISL7998X_REG_PX_DEC_HUE(pg)		ISL7998X_REG((pg), 0x15)109#define ISL7998X_REG_PX_DEC_VERT_PEAK(pg)	ISL7998X_REG((pg), 0x17)110#define ISL7998X_REG_PX_DEC_CORING(pg)		ISL7998X_REG((pg), 0x18)111#define ISL7998X_REG_PX_DEC_SDT(pg)		ISL7998X_REG((pg), 0x1c)112#define ISL7998X_REG_PX_DEC_SDT_DET		BIT(7)113#define ISL7998X_REG_PX_DEC_SDT_NOW		GENMASK(6, 4)114#define ISL7998X_REG_PX_DEC_SDT_STANDARD	GENMASK(2, 0)115#define ISL7998X_REG_PX_DEC_SDT_STANDARD_NTSC_M		0116#define ISL7998X_REG_PX_DEC_SDT_STANDARD_PAL		1117#define ISL7998X_REG_PX_DEC_SDT_STANDARD_SECAM		2118#define ISL7998X_REG_PX_DEC_SDT_STANDARD_NTSC_443	3119#define ISL7998X_REG_PX_DEC_SDT_STANDARD_PAL_M		4120#define ISL7998X_REG_PX_DEC_SDT_STANDARD_PAL_CN		5121#define ISL7998X_REG_PX_DEC_SDT_STANDARD_PAL_60		6122#define ISL7998X_REG_PX_DEC_SDT_STANDARD_UNKNOWN	7123#define ISL7998X_REG_PX_DEC_SDTR(pg)		ISL7998X_REG((pg), 0x1d)124#define ISL7998X_REG_PX_DEC_SDTR_ATSTART	BIT(7)125#define ISL7998X_REG_PX_DEC_CLMPG(pg)		ISL7998X_REG((pg), 0x20)126#define ISL7998X_REG_PX_DEC_IAGC(pg)		ISL7998X_REG((pg), 0x21)127#define ISL7998X_REG_PX_DEC_AGCGAIN(pg)		ISL7998X_REG((pg), 0x22)128#define ISL7998X_REG_PX_DEC_PEAKWT(pg)		ISL7998X_REG((pg), 0x23)129#define ISL7998X_REG_PX_DEC_CLMPL(pg)		ISL7998X_REG((pg), 0x24)130#define ISL7998X_REG_PX_DEC_SYNCT(pg)		ISL7998X_REG((pg), 0x25)131#define ISL7998X_REG_PX_DEC_MISSCNT(pg)		ISL7998X_REG((pg), 0x26)132#define ISL7998X_REG_PX_DEC_PCLAMP(pg)		ISL7998X_REG((pg), 0x27)133#define ISL7998X_REG_PX_DEC_VERT_CTL_1(pg)	ISL7998X_REG((pg), 0x28)134#define ISL7998X_REG_PX_DEC_VERT_CTL_2(pg)	ISL7998X_REG((pg), 0x29)135#define ISL7998X_REG_PX_DEC_CLR_KILL_LVL(pg)	ISL7998X_REG((pg), 0x2a)136#define ISL7998X_REG_PX_DEC_COMB_FILTER_CTL(pg)	ISL7998X_REG((pg), 0x2b)137#define ISL7998X_REG_PX_DEC_LUMA_DELAY(pg)	ISL7998X_REG((pg), 0x2c)138#define ISL7998X_REG_PX_DEC_MISC1(pg)		ISL7998X_REG((pg), 0x2d)139#define ISL7998X_REG_PX_DEC_MISC2(pg)		ISL7998X_REG((pg), 0x2e)140#define ISL7998X_REG_PX_DEC_MISC3(pg)		ISL7998X_REG((pg), 0x2f)141#define ISL7998X_REG_PX_DEC_MVSN(pg)		ISL7998X_REG((pg), 0x30)142#define ISL7998X_REG_PX_DEC_CSTATUS2(pg)	ISL7998X_REG((pg), 0x31)143#define ISL7998X_REG_PX_DEC_HFREF(pg)		ISL7998X_REG((pg), 0x32)144#define ISL7998X_REG_PX_DEC_CLMD(pg)		ISL7998X_REG((pg), 0x33)145#define ISL7998X_REG_PX_DEC_ID_DET_CTL(pg)	ISL7998X_REG((pg), 0x34)146#define ISL7998X_REG_PX_DEC_CLCNTL(pg)		ISL7998X_REG((pg), 0x35)147#define ISL7998X_REG_PX_DEC_DIFF_CLMP_CTL_1(pg)	ISL7998X_REG((pg), 0x36)148#define ISL7998X_REG_PX_DEC_DIFF_CLMP_CTL_2(pg)	ISL7998X_REG((pg), 0x37)149#define ISL7998X_REG_PX_DEC_DIFF_CLMP_CTL_3(pg)	ISL7998X_REG((pg), 0x38)150#define ISL7998X_REG_PX_DEC_DIFF_CLMP_CTL_4(pg)	ISL7998X_REG((pg), 0x39)151#define ISL7998X_REG_PX_DEC_SHORT_DET_CTL(pg)	ISL7998X_REG((pg), 0x3a)152#define ISL7998X_REG_PX_DEC_SHORT_DET_CTL_1(pg)	ISL7998X_REG((pg), 0x3b)153#define ISL7998X_REG_PX_DEC_AFE_TST_MUX_CTL(pg)	ISL7998X_REG((pg), 0x3c)154#define ISL7998X_REG_PX_DEC_DATA_CONV(pg)	ISL7998X_REG((pg), 0x3d)155#define ISL7998X_REG_PX_DEC_INTERNAL_TEST(pg)	ISL7998X_REG((pg), 0x3f)156#define ISL7998X_REG_PX_DEC_H_DELAY_CTL(pg)	ISL7998X_REG((pg), 0x43)157#define ISL7998X_REG_PX_DEC_H_DELAY_II_HI(pg)	ISL7998X_REG((pg), 0x44)158#define ISL7998X_REG_PX_DEC_H_DELAY_II_LOW(pg)	ISL7998X_REG((pg), 0x45)159 160#define ISL7998X_REG_PX_ACA_CTL_1(pg)		ISL7998X_REG((pg), 0x80)161#define ISL7998X_REG_PX_ACA_GAIN_CTL(pg)	ISL7998X_REG((pg), 0x81)162#define ISL7998X_REG_PX_ACA_Y_AVG_HI_LIMIT(pg)	ISL7998X_REG((pg), 0x82)163#define ISL7998X_REG_PX_ACA_Y_AVG_LO_LIMIT(pg)	ISL7998X_REG((pg), 0x83)164#define ISL7998X_REG_PX_ACA_Y_DET_THRESHOLD(pg)	ISL7998X_REG((pg), 0x84)165#define ISL7998X_REG_PX_ACA_BLACK_LVL(pg)	ISL7998X_REG((pg), 0x85)166#define ISL7998X_REG_PX_ACA_CENTER_LVL(pg)	ISL7998X_REG((pg), 0x86)167#define ISL7998X_REG_PX_ACA_WHITE_LVL(pg)	ISL7998X_REG((pg), 0x87)168#define ISL7998X_REG_PX_ACA_MEAN_OFF_LIMIT(pg)	ISL7998X_REG((pg), 0x88)169#define ISL7998X_REG_PX_ACA_MEAN_OFF_UPGAIN(pg)	ISL7998X_REG((pg), 0x89)170#define ISL7998X_REG_PX_ACA_MEAN_OFF_SLOPE(pg)	ISL7998X_REG((pg), 0x8a)171#define ISL7998X_REG_PX_ACA_MEAN_OFF_DNGAIN(pg)	ISL7998X_REG((pg), 0x8b)172#define ISL7998X_REG_PX_ACA_DELTA_CO_THRES(pg)	ISL7998X_REG((pg), 0x8c)173#define ISL7998X_REG_PX_ACA_DELTA_SLOPE(pg)	ISL7998X_REG((pg), 0x8d)174#define ISL7998X_REG_PX_ACA_LO_HI_AVG_THRES(pg)	ISL7998X_REG((pg), 0x8e)175#define ISL7998X_REG_PX_ACA_LO_MAX_LVL_CTL(pg)	ISL7998X_REG((pg), 0x8f)176#define ISL7998X_REG_PX_ACA_HI_MAX_LVL_CTL(pg)	ISL7998X_REG((pg), 0x90)177#define ISL7998X_REG_PX_ACA_LO_UPGAIN_CTL(pg)	ISL7998X_REG((pg), 0x91)178#define ISL7998X_REG_PX_ACA_LO_DNGAIN_CTL(pg)	ISL7998X_REG((pg), 0x92)179#define ISL7998X_REG_PX_ACA_HI_UPGAIN_CTL(pg)	ISL7998X_REG((pg), 0x93)180#define ISL7998X_REG_PX_ACA_HI_DNGAIN_CTL(pg)	ISL7998X_REG((pg), 0x94)181#define ISL7998X_REG_PX_ACA_LOPASS_FLT_COEF(pg)	ISL7998X_REG((pg), 0x95)182#define ISL7998X_REG_PX_ACA_PDF_INDEX(pg)	ISL7998X_REG((pg), 0x96)183#define ISL7998X_REG_PX_ACA_HIST_WIN_H_STT(pg)	ISL7998X_REG((pg), 0x97)184#define ISL7998X_REG_PX_ACA_HIST_WIN_H_SZ1(pg)	ISL7998X_REG((pg), 0x98)185#define ISL7998X_REG_PX_ACA_HIST_WIN_H_SZ2(pg)	ISL7998X_REG((pg), 0x99)186#define ISL7998X_REG_PX_ACA_HIST_WIN_V_STT(pg)	ISL7998X_REG((pg), 0x9a)187#define ISL7998X_REG_PX_ACA_HIST_WIN_V_SZ1(pg)	ISL7998X_REG((pg), 0x9b)188#define ISL7998X_REG_PX_ACA_HIST_WIN_V_SZ2(pg)	ISL7998X_REG((pg), 0x9c)189#define ISL7998X_REG_PX_ACA_Y_AVG(pg)		ISL7998X_REG((pg), 0xa0)190#define ISL7998X_REG_PX_ACA_Y_AVG_LIM(pg)	ISL7998X_REG((pg), 0xa1)191#define ISL7998X_REG_PX_ACA_LO_AVG(pg)		ISL7998X_REG((pg), 0xa2)192#define ISL7998X_REG_PX_ACA_HI_AVG(pg)		ISL7998X_REG((pg), 0xa3)193#define ISL7998X_REG_PX_ACA_Y_MAX(pg)		ISL7998X_REG((pg), 0xa4)194#define ISL7998X_REG_PX_ACA_Y_MIN(pg)		ISL7998X_REG((pg), 0xa5)195#define ISL7998X_REG_PX_ACA_MOFFSET(pg)		ISL7998X_REG((pg), 0xa6)196#define ISL7998X_REG_PX_ACA_LO_GAIN(pg)		ISL7998X_REG((pg), 0xa7)197#define ISL7998X_REG_PX_ACA_HI_GAIN(pg)		ISL7998X_REG((pg), 0xa8)198#define ISL7998X_REG_PX_ACA_LL_SLOPE(pg)	ISL7998X_REG((pg), 0xa9)199#define ISL7998X_REG_PX_ACA_LH_SLOPE(pg)	ISL7998X_REG((pg), 0xaa)200#define ISL7998X_REG_PX_ACA_HL_SLOPE(pg)	ISL7998X_REG((pg), 0xab)201#define ISL7998X_REG_PX_ACA_HH_SLOPE(pg)	ISL7998X_REG((pg), 0xac)202#define ISL7998X_REG_PX_ACA_X_LOW(pg)		ISL7998X_REG((pg), 0xad)203#define ISL7998X_REG_PX_ACA_X_MEAN(pg)		ISL7998X_REG((pg), 0xae)204#define ISL7998X_REG_PX_ACA_X_HIGH(pg)		ISL7998X_REG((pg), 0xaf)205#define ISL7998X_REG_PX_ACA_Y_LOW(pg)		ISL7998X_REG((pg), 0xb0)206#define ISL7998X_REG_PX_ACA_Y_MEAN(pg)		ISL7998X_REG((pg), 0xb1)207#define ISL7998X_REG_PX_ACA_Y_HIGH(pg)		ISL7998X_REG((pg), 0xb2)208#define ISL7998X_REG_PX_ACA_CTL_2(pg)		ISL7998X_REG((pg), 0xb3)209#define ISL7998X_REG_PX_ACA_CTL_3(pg)		ISL7998X_REG((pg), 0xb4)210#define ISL7998X_REG_PX_ACA_CTL_4(pg)		ISL7998X_REG((pg), 0xb5)211#define ISL7998X_REG_PX_ACA_FLEX_WIN_HIST(pg)	ISL7998X_REG((pg), 0xc0)212#define ISL7998X_REG_PX_ACA_FLEX_WIN_X_TL_H(pg)	ISL7998X_REG((pg), 0xc1)213#define ISL7998X_REG_PX_ACA_FLEX_WIN_X_TL_L(pg)	ISL7998X_REG((pg), 0xc2)214#define ISL7998X_REG_PX_ACA_FLEX_WIN_Y_TL_H(pg)	ISL7998X_REG((pg), 0xc3)215#define ISL7998X_REG_PX_ACA_FLEX_WIN_Y_TL_L(pg)	ISL7998X_REG((pg), 0xc4)216#define ISL7998X_REG_PX_ACA_FLEX_WIN_X_TR_H(pg)	ISL7998X_REG((pg), 0xc5)217#define ISL7998X_REG_PX_ACA_FLEX_WIN_X_TR_L(pg)	ISL7998X_REG((pg), 0xc6)218#define ISL7998X_REG_PX_ACA_FLEX_WIN_Y_TR_H(pg)	ISL7998X_REG((pg), 0xc7)219#define ISL7998X_REG_PX_ACA_FLEX_WIN_Y_TR_L(pg)	ISL7998X_REG((pg), 0xc8)220#define ISL7998X_REG_PX_ACA_FLEX_WIN_X_BL_H(pg)	ISL7998X_REG((pg), 0xc9)221#define ISL7998X_REG_PX_ACA_FLEX_WIN_X_BL_L(pg)	ISL7998X_REG((pg), 0xca)222#define ISL7998X_REG_PX_ACA_FLEX_WIN_Y_BL_H(pg)	ISL7998X_REG((pg), 0xcb)223#define ISL7998X_REG_PX_ACA_FLEX_WIN_Y_BL_L(pg)	ISL7998X_REG((pg), 0xcc)224#define ISL7998X_REG_PX_ACA_FLEX_WIN_X_BR_H(pg)	ISL7998X_REG((pg), 0xcd)225#define ISL7998X_REG_PX_ACA_FLEX_WIN_X_BR_L(pg)	ISL7998X_REG((pg), 0xce)226#define ISL7998X_REG_PX_ACA_FLEX_WIN_Y_BR_H(pg)	ISL7998X_REG((pg), 0xcf)227#define ISL7998X_REG_PX_ACA_FLEX_WIN_Y_BR_L(pg)	ISL7998X_REG((pg), 0xd0)228#define ISL7998X_REG_PX_ACA_FLEX_WIN_X_LM_H(pg)	ISL7998X_REG((pg), 0xd1)229#define ISL7998X_REG_PX_ACA_FLEX_WIN_X_LM_L(pg)	ISL7998X_REG((pg), 0xd2)230#define ISL7998X_REG_PX_ACA_FLEX_WIN_Y_LM_H(pg)	ISL7998X_REG((pg), 0xd3)231#define ISL7998X_REG_PX_ACA_FLEX_WIN_Y_LM_L(pg)	ISL7998X_REG((pg), 0xd4)232#define ISL7998X_REG_PX_ACA_FLEX_WIN_X_TM_H(pg)	ISL7998X_REG((pg), 0xd5)233#define ISL7998X_REG_PX_ACA_FLEX_WIN_X_TM_L(pg)	ISL7998X_REG((pg), 0xd6)234#define ISL7998X_REG_PX_ACA_FLEX_WIN_Y_TM_H(pg)	ISL7998X_REG((pg), 0xd7)235#define ISL7998X_REG_PX_ACA_FLEX_WIN_Y_TM_L(pg)	ISL7998X_REG((pg), 0xd8)236#define ISL7998X_REG_PX_ACA_FLEX_WIN_X_BM_H(pg)	ISL7998X_REG((pg), 0xd9)237#define ISL7998X_REG_PX_ACA_FLEX_WIN_X_BM_L(pg)	ISL7998X_REG((pg), 0xda)238#define ISL7998X_REG_PX_ACA_FLEX_WIN_Y_BM_H(pg)	ISL7998X_REG((pg), 0xdb)239#define ISL7998X_REG_PX_ACA_FLEX_WIN_Y_BM_L(pg)	ISL7998X_REG((pg), 0xdc)240#define ISL7998X_REG_PX_ACA_FLEX_WIN_X_RM_H(pg)	ISL7998X_REG((pg), 0xdd)241#define ISL7998X_REG_PX_ACA_FLEX_WIN_X_RM_L(pg)	ISL7998X_REG((pg), 0xde)242#define ISL7998X_REG_PX_ACA_FLEX_WIN_Y_RM_H(pg)	ISL7998X_REG((pg), 0xdf)243#define ISL7998X_REG_PX_ACA_FLEX_WIN_Y_RM_L(pg)	ISL7998X_REG((pg), 0xe0)244#define ISL7998X_REG_PX_ACA_HIST_DATA_LO(pg)	ISL7998X_REG((pg), 0xe1)245#define ISL7998X_REG_PX_ACA_HIST_DATA_MID(pg)	ISL7998X_REG((pg), 0xe2)246#define ISL7998X_REG_PX_ACA_HIST_DATA_HI(pg)	ISL7998X_REG((pg), 0xe3)247#define ISL7998X_REG_PX_ACA_FLEX_WIN_Y_CLR(pg)	ISL7998X_REG((pg), 0xe4)248#define ISL7998X_REG_PX_ACA_FLEX_WIN_CB_CLR(pg)	ISL7998X_REG((pg), 0xe5)249#define ISL7998X_REG_PX_ACA_FLEX_WIN_CR_CLR(pg)	ISL7998X_REG((pg), 0xe6)250#define ISL7998X_REG_PX_ACA_XFER_HIST_HOST(pg)	ISL7998X_REG((pg), 0xe7)251 252#define ISL7998X_REG_P5_LI_ENGINE_CTL		ISL7998X_REG(5, 0x00)253#define ISL7998X_REG_P5_LI_ENGINE_LINE_CTL	ISL7998X_REG(5, 0x01)254#define ISL7998X_REG_P5_LI_ENGINE_PIC_WIDTH	ISL7998X_REG(5, 0x02)255#define ISL7998X_REG_P5_LI_ENGINE_SYNC_CTL	ISL7998X_REG(5, 0x03)256#define ISL7998X_REG_P5_LI_ENGINE_VC_ASSIGNMENT	ISL7998X_REG(5, 0x04)257#define ISL7998X_REG_P5_LI_ENGINE_TYPE_CTL	ISL7998X_REG(5, 0x05)258#define ISL7998X_REG_P5_LI_ENGINE_FIFO_CTL	ISL7998X_REG(5, 0x06)259#define ISL7998X_REG_P5_MIPI_READ_START_CTL	ISL7998X_REG(5, 0x07)260#define ISL7998X_REG_P5_PSEUDO_FRM_FIELD_CTL	ISL7998X_REG(5, 0x08)261#define ISL7998X_REG_P5_ONE_FIELD_MODE_CTL	ISL7998X_REG(5, 0x09)262#define ISL7998X_REG_P5_MIPI_INT_HW_TST_CTR	ISL7998X_REG(5, 0x0a)263#define ISL7998X_REG_P5_TP_GEN_BAR_PATTERN	ISL7998X_REG(5, 0x0b)264#define ISL7998X_REG_P5_MIPI_PCNT_PSFRM		ISL7998X_REG(5, 0x0c)265#define ISL7998X_REG_P5_LI_ENGINE_TP_GEN_CTL	ISL7998X_REG(5, 0x0d)266#define ISL7998X_REG_P5_MIPI_VBLANK_PSFRM	ISL7998X_REG(5, 0x0e)267#define ISL7998X_REG_P5_LI_ENGINE_CTL_2		ISL7998X_REG(5, 0x0f)268#define ISL7998X_REG_P5_MIPI_WCNT_1		ISL7998X_REG(5, 0x10)269#define ISL7998X_REG_P5_MIPI_WCNT_2		ISL7998X_REG(5, 0x11)270#define ISL7998X_REG_P5_MIPI_DPHY_TIMING_CTL_1	ISL7998X_REG(5, 0x12)271#define ISL7998X_REG_P5_MIPI_DPHY_TIMING_CTL_2	ISL7998X_REG(5, 0x13)272#define ISL7998X_REG_P5_MIPI_DPHY_TIMING_CTL_3	ISL7998X_REG(5, 0x14)273#define ISL7998X_REG_P5_MIPI_DPHY_TIMING_CTL_4	ISL7998X_REG(5, 0x15)274#define ISL7998X_REG_P5_MIPI_DPHY_TIMING_CTL_5	ISL7998X_REG(5, 0x16)275#define ISL7998X_REG_P5_MIPI_DPHY_TIMING_CTL_6	ISL7998X_REG(5, 0x17)276#define ISL7998X_REG_P5_MIPI_DPHY_PARAMS_1	ISL7998X_REG(5, 0x18)277#define ISL7998X_REG_P5_MIPI_DPHY_SOT_PERIOD	ISL7998X_REG(5, 0x19)278#define ISL7998X_REG_P5_MIPI_DPHY_EOT_PERIOD	ISL7998X_REG(5, 0x1a)279#define ISL7998X_REG_P5_MIPI_DPHY_PARAMS_2	ISL7998X_REG(5, 0x1b)280#define ISL7998X_REG_P5_MIPI_DPHY_TIMING_CTL_7	ISL7998X_REG(5, 0x1c)281#define ISL7998X_REG_P5_MIPI_DPHY_TIMING_CTL_8	ISL7998X_REG(5, 0x1d)282#define ISL7998X_REG_P5_MIPI_DPHY_TIMING_CTL_9	ISL7998X_REG(5, 0x1e)283#define ISL7998X_REG_P5_MIPI_DPHY_TIMING_CTL_10	ISL7998X_REG(5, 0x1f)284#define ISL7998X_REG_P5_TP_GEN_MIPI		ISL7998X_REG(5, 0x20)285#define ISL7998X_REG_P5_ESC_MODE_TIME_CTL	ISL7998X_REG(5, 0x21)286#define ISL7998X_REG_P5_AUTO_TEST_ERR_DET	ISL7998X_REG(5, 0x22)287#define ISL7998X_REG_P5_MIPI_TIMING		ISL7998X_REG(5, 0x23)288#define ISL7998X_REG_P5_PIC_HEIGHT_HIGH		ISL7998X_REG(5, 0x24)289#define ISL7998X_REG_P5_PIC_HEIGHT_LOW		ISL7998X_REG(5, 0x25)290#define ISL7998X_REG_P5_MIPI_SP_HS_TRL_CTL	ISL7998X_REG(5, 0x26)291#define ISL7998X_REG_P5_FIFO_THRSH_CNT_1	ISL7998X_REG(5, 0x28)292#define ISL7998X_REG_P5_FIFO_THRSH_CNT_2	ISL7998X_REG(5, 0x29)293#define ISL7998X_REG_P5_TP_GEN_RND_SYNC_CTL_1	ISL7998X_REG(5, 0x2a)294#define ISL7998X_REG_P5_TP_GEN_RND_SYNC_CTL_2	ISL7998X_REG(5, 0x2b)295#define ISL7998X_REG_P5_PSF_FIELD_END_CTL_1	ISL7998X_REG(5, 0x2c)296#define ISL7998X_REG_P5_PSF_FIELD_END_CTL_2	ISL7998X_REG(5, 0x2d)297#define ISL7998X_REG_P5_PSF_FIELD_END_CTL_3	ISL7998X_REG(5, 0x2e)298#define ISL7998X_REG_P5_PSF_FIELD_END_CTL_4	ISL7998X_REG(5, 0x2f)299#define ISL7998X_REG_P5_MIPI_ANA_DATA_CTL_1	ISL7998X_REG(5, 0x30)300#define ISL7998X_REG_P5_MIPI_ANA_DATA_CTL_2	ISL7998X_REG(5, 0x31)301#define ISL7998X_REG_P5_MIPI_ANA_CLK_CTL	ISL7998X_REG(5, 0x32)302#define ISL7998X_REG_P5_PLL_ANA_STATUS		ISL7998X_REG(5, 0x33)303#define ISL7998X_REG_P5_PLL_ANA_MISC_CTL	ISL7998X_REG(5, 0x34)304#define ISL7998X_REG_P5_MIPI_ANA		ISL7998X_REG(5, 0x35)305#define ISL7998X_REG_P5_PLL_ANA			ISL7998X_REG(5, 0x36)306#define ISL7998X_REG_P5_TOTAL_PF_LINE_CNT_1	ISL7998X_REG(5, 0x38)307#define ISL7998X_REG_P5_TOTAL_PF_LINE_CNT_2	ISL7998X_REG(5, 0x39)308#define ISL7998X_REG_P5_H_LINE_CNT_1		ISL7998X_REG(5, 0x3a)309#define ISL7998X_REG_P5_H_LINE_CNT_2		ISL7998X_REG(5, 0x3b)310#define ISL7998X_REG_P5_HIST_LINE_CNT_1		ISL7998X_REG(5, 0x3c)311#define ISL7998X_REG_P5_HIST_LINE_CNT_2		ISL7998X_REG(5, 0x3d)312 313static const struct reg_sequence isl7998x_init_seq_1[] = {314	{ ISL7998X_REG_P0_SHORT_DIAG_IRQ_EN, 0xff },315	{ ISL7998X_REG_PX_DEC_SDT(0x1), 0x00 },316	{ ISL7998X_REG_PX_DEC_SHORT_DET_CTL_1(0x1), 0x03 },317	{ ISL7998X_REG_PX_DEC_SDT(0x2), 0x00 },318	{ ISL7998X_REG_PX_DEC_SHORT_DET_CTL_1(0x2), 0x03 },319	{ ISL7998X_REG_PX_DEC_SDT(0x3), 0x00 },320	{ ISL7998X_REG_PX_DEC_SHORT_DET_CTL_1(0x3), 0x03 },321	{ ISL7998X_REG_PX_DEC_SDT(0x4), 0x00 },322	{ ISL7998X_REG_PX_DEC_SHORT_DET_CTL_1(0x4), 0x03 },323	{ ISL7998X_REG_P5_LI_ENGINE_CTL, 0x00 },324	{ ISL7998X_REG_P0_SW_RESET_CTL, 0x1f, 10 },325	{ ISL7998X_REG_P0_IO_BUFFER_CTL, 0x00 },326	{ ISL7998X_REG_P0_MPP2_SYNC_CTL, 0xc9 },327	{ ISL7998X_REG_P0_IRQ_SYNC_CTL, 0xc9 },328	{ ISL7998X_REG_P0_CHAN_1_IRQ, 0x03 },329	{ ISL7998X_REG_P0_CHAN_2_IRQ, 0x00 },330	{ ISL7998X_REG_P0_CHAN_3_IRQ, 0x00 },331	{ ISL7998X_REG_P0_CHAN_4_IRQ, 0x00 },332	{ ISL7998X_REG_P5_LI_ENGINE_CTL, 0x02 },333	{ ISL7998X_REG_P5_LI_ENGINE_LINE_CTL, 0x85 },334	{ ISL7998X_REG_P5_LI_ENGINE_PIC_WIDTH, 0xa0 },335	{ ISL7998X_REG_P5_LI_ENGINE_SYNC_CTL, 0x18 },336	{ ISL7998X_REG_P5_LI_ENGINE_TYPE_CTL, 0x40 },337	{ ISL7998X_REG_P5_LI_ENGINE_FIFO_CTL, 0x40 },338	{ ISL7998X_REG_P5_MIPI_WCNT_1, 0x05 },339	{ ISL7998X_REG_P5_MIPI_WCNT_2, 0xa0 },340	{ ISL7998X_REG_P5_TP_GEN_MIPI, 0x00 },341	{ ISL7998X_REG_P5_ESC_MODE_TIME_CTL, 0x0c },342	{ ISL7998X_REG_P5_MIPI_SP_HS_TRL_CTL, 0x00 },343	{ ISL7998X_REG_P5_TP_GEN_RND_SYNC_CTL_1, 0x00 },344	{ ISL7998X_REG_P5_TP_GEN_RND_SYNC_CTL_2, 0x19 },345	{ ISL7998X_REG_P5_PSF_FIELD_END_CTL_1, 0x18 },346	{ ISL7998X_REG_P5_PSF_FIELD_END_CTL_2, 0xf1 },347	{ ISL7998X_REG_P5_PSF_FIELD_END_CTL_3, 0x00 },348	{ ISL7998X_REG_P5_PSF_FIELD_END_CTL_4, 0xf1 },349	{ ISL7998X_REG_P5_MIPI_ANA_DATA_CTL_1, 0x00 },350	{ ISL7998X_REG_P5_MIPI_ANA_DATA_CTL_2, 0x00 },351	{ ISL7998X_REG_P5_MIPI_ANA_CLK_CTL, 0x00 },352	{ ISL7998X_REG_P5_PLL_ANA_STATUS, 0xc0 },353	{ ISL7998X_REG_P5_PLL_ANA_MISC_CTL, 0x18 },354	{ ISL7998X_REG_P5_PLL_ANA, 0x00 },355	{ ISL7998X_REG_P0_SW_RESET_CTL, 0x10, 10 },356	/* Page 0xf means write to all of pages 1,2,3,4 */357	{ ISL7998X_REG_PX_DEC_VDELAY_LO(0xf), 0x14 },358	{ ISL7998X_REG_PX_DEC_MISC3(0xf), 0xe6 },359	{ ISL7998X_REG_PX_DEC_CLMD(0xf), 0x85 },360	{ ISL7998X_REG_PX_DEC_H_DELAY_II_LOW(0xf), 0x11 },361	{ ISL7998X_REG_PX_ACA_XFER_HIST_HOST(0xf), 0x00 },362	{ ISL7998X_REG_P0_CLK_CTL_1, 0x1f },363	{ ISL7998X_REG_P0_CLK_CTL_2, 0x43 },364	{ ISL7998X_REG_P0_CLK_CTL_3, 0x4f },365};366 367static const struct reg_sequence isl7998x_init_seq_2[] = {368	{ ISL7998X_REG_P5_LI_ENGINE_SYNC_CTL, 0x10 },369	{ ISL7998X_REG_P5_LI_ENGINE_VC_ASSIGNMENT, 0xe4 },370	{ ISL7998X_REG_P5_LI_ENGINE_TYPE_CTL, 0x00 },371	{ ISL7998X_REG_P5_LI_ENGINE_FIFO_CTL, 0x60 },372	{ ISL7998X_REG_P5_MIPI_READ_START_CTL, 0x2b },373	{ ISL7998X_REG_P5_PSEUDO_FRM_FIELD_CTL, 0x02 },374	{ ISL7998X_REG_P5_ONE_FIELD_MODE_CTL, 0x00 },375	{ ISL7998X_REG_P5_MIPI_INT_HW_TST_CTR, 0x62 },376	{ ISL7998X_REG_P5_TP_GEN_BAR_PATTERN, 0x02 },377	{ ISL7998X_REG_P5_MIPI_PCNT_PSFRM, 0x36 },378	{ ISL7998X_REG_P5_LI_ENGINE_TP_GEN_CTL, 0x00 },379	{ ISL7998X_REG_P5_MIPI_VBLANK_PSFRM, 0x6c },380	{ ISL7998X_REG_P5_LI_ENGINE_CTL_2, 0x00 },381	{ ISL7998X_REG_P5_MIPI_WCNT_1, 0x05 },382	{ ISL7998X_REG_P5_MIPI_WCNT_2, 0xa0 },383	{ ISL7998X_REG_P5_MIPI_DPHY_TIMING_CTL_1, 0x77 },384	{ ISL7998X_REG_P5_MIPI_DPHY_TIMING_CTL_2, 0x17 },385	{ ISL7998X_REG_P5_MIPI_DPHY_TIMING_CTL_3, 0x08 },386	{ ISL7998X_REG_P5_MIPI_DPHY_TIMING_CTL_4, 0x38 },387	{ ISL7998X_REG_P5_MIPI_DPHY_TIMING_CTL_5, 0x14 },388	{ ISL7998X_REG_P5_MIPI_DPHY_TIMING_CTL_6, 0xf6 },389	{ ISL7998X_REG_P5_MIPI_DPHY_PARAMS_1, 0x00 },390	{ ISL7998X_REG_P5_MIPI_DPHY_SOT_PERIOD, 0x17 },391	{ ISL7998X_REG_P5_MIPI_DPHY_EOT_PERIOD, 0x0a },392	{ ISL7998X_REG_P5_MIPI_DPHY_PARAMS_2, 0x71 },393	{ ISL7998X_REG_P5_MIPI_DPHY_TIMING_CTL_7, 0x7a },394	{ ISL7998X_REG_P5_MIPI_DPHY_TIMING_CTL_8, 0x0f },395	{ ISL7998X_REG_P5_MIPI_DPHY_TIMING_CTL_9, 0x8c },396	{ ISL7998X_REG_P5_MIPI_SP_HS_TRL_CTL, 0x08 },397	{ ISL7998X_REG_P5_FIFO_THRSH_CNT_1, 0x01 },398	{ ISL7998X_REG_P5_FIFO_THRSH_CNT_2, 0x0e },399	{ ISL7998X_REG_P5_TP_GEN_RND_SYNC_CTL_1, 0x00 },400	{ ISL7998X_REG_P5_TP_GEN_RND_SYNC_CTL_2, 0x00 },401	{ ISL7998X_REG_P5_TOTAL_PF_LINE_CNT_1, 0x03 },402	{ ISL7998X_REG_P5_TOTAL_PF_LINE_CNT_2, 0xc0 },403	{ ISL7998X_REG_P5_H_LINE_CNT_1, 0x06 },404	{ ISL7998X_REG_P5_H_LINE_CNT_2, 0xb3 },405	{ ISL7998X_REG_P5_HIST_LINE_CNT_1, 0x00 },406	{ ISL7998X_REG_P5_HIST_LINE_CNT_2, 0xf1 },407	{ ISL7998X_REG_P5_LI_ENGINE_FIFO_CTL, 0x00 },408	{ ISL7998X_REG_P5_MIPI_ANA, 0x00 },409	/*410	 * Wait a bit after reset so that the chip can capture a frame411	 * and update internal line counters.412	 */413	{ ISL7998X_REG_P0_SW_RESET_CTL, 0x00, 50 },414};415 416enum isl7998x_pads {417	ISL7998X_PAD_OUT,418	ISL7998X_PAD_VIN1,419	ISL7998X_PAD_VIN2,420	ISL7998X_PAD_VIN3,421	ISL7998X_PAD_VIN4,422	ISL7998X_NUM_PADS423};424 425struct isl7998x_datafmt {426	u32			code;427	enum v4l2_colorspace	colorspace;428};429 430static const struct isl7998x_datafmt isl7998x_colour_fmts[] = {431	{ MEDIA_BUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_SRGB },432};433 434/* Menu items for LINK_FREQ V4L2 control */435static const s64 link_freq_menu_items[] = {436	/* 1 channel, 1 lane or 2 channels, 2 lanes */437	108000000,438	/* 2 channels, 1 lane or 4 channels, 2 lanes */439	216000000,440	/* 4 channels, 1 lane */441	432000000,442};443 444/* Menu items for TEST_PATTERN V4L2 control */445static const char * const isl7998x_test_pattern_menu[] = {446	"Disabled",447	"Enabled",448};449 450static const char * const isl7998x_test_pattern_bars[] = {451	"bbbbwb", "bbbwwb", "bbwbwb", "bbwwwb",452};453 454static const char * const isl7998x_test_pattern_colors[] = {455	"Yellow", "Blue", "Green", "Pink",456};457 458struct isl7998x_mode {459	unsigned int width;460	unsigned int height;461	enum v4l2_field field;462};463 464static const struct isl7998x_mode supported_modes[] = {465	{466		.width = 720,467		.height = 576,468		.field = V4L2_FIELD_SEQ_TB,469	},470	{471		.width = 720,472		.height = 480,473		.field = V4L2_FIELD_SEQ_BT,474	},475};476 477static const struct isl7998x_video_std {478	const v4l2_std_id norm;479	unsigned int id;480	const struct isl7998x_mode *mode;481} isl7998x_std_res[] = {482	{ V4L2_STD_NTSC_443,483	  ISL7998X_REG_PX_DEC_SDT_STANDARD_NTSC_443,484	  &supported_modes[1] },485	{ V4L2_STD_PAL_M,486	  ISL7998X_REG_PX_DEC_SDT_STANDARD_PAL_M,487	  &supported_modes[1] },488	{ V4L2_STD_PAL_Nc,489	  ISL7998X_REG_PX_DEC_SDT_STANDARD_PAL_CN,490	  &supported_modes[0] },491	{ V4L2_STD_PAL_N,492	  ISL7998X_REG_PX_DEC_SDT_STANDARD_PAL,493	  &supported_modes[0] },494	{ V4L2_STD_PAL_60,495	  ISL7998X_REG_PX_DEC_SDT_STANDARD_PAL_60,496	  &supported_modes[1] },497	{ V4L2_STD_NTSC,498	  ISL7998X_REG_PX_DEC_SDT_STANDARD_NTSC_M,499	  &supported_modes[1] },500	{ V4L2_STD_PAL,501	  ISL7998X_REG_PX_DEC_SDT_STANDARD_PAL,502	  &supported_modes[0] },503	{ V4L2_STD_SECAM,504	  ISL7998X_REG_PX_DEC_SDT_STANDARD_SECAM,505	  &supported_modes[0] },506	{ V4L2_STD_UNKNOWN,507	  ISL7998X_REG_PX_DEC_SDT_STANDARD_UNKNOWN,508	  &supported_modes[1] },509};510 511struct isl7998x {512	struct v4l2_subdev		subdev;513	struct regmap			*regmap;514	struct gpio_desc		*pd_gpio;515	struct gpio_desc		*rstb_gpio;516	unsigned int			nr_mipi_lanes;517	u32				nr_inputs;518 519	const struct isl7998x_datafmt	*fmt;520	v4l2_std_id			norm;521	struct media_pad		pads[ISL7998X_NUM_PADS];522 523	int				enabled;524 525	/* protect fmt, norm, enabled */526	struct mutex			lock;527 528	struct v4l2_ctrl_handler	ctrl_handler;529	/* protect ctrl_handler */530	struct mutex			ctrl_mutex;531 532	/* V4L2 Controls */533	struct v4l2_ctrl		*link_freq;534	u8				test_pattern;535	u8				test_pattern_bars;536	u8				test_pattern_chans;537	u8				test_pattern_color;538};539 540static struct isl7998x *sd_to_isl7998x(struct v4l2_subdev *sd)541{542	return container_of(sd, struct isl7998x, subdev);543}544 545static struct isl7998x *i2c_to_isl7998x(const struct i2c_client *client)546{547	return sd_to_isl7998x(i2c_get_clientdata(client));548}549 550static unsigned int isl7998x_norm_to_val(v4l2_std_id norm)551{552	unsigned int i;553 554	for (i = 0; i < ARRAY_SIZE(isl7998x_std_res); i++)555		if (isl7998x_std_res[i].norm & norm)556			break;557	if (i == ARRAY_SIZE(isl7998x_std_res))558		return ISL7998X_REG_PX_DEC_SDT_STANDARD_UNKNOWN;559 560	return isl7998x_std_res[i].id;561}562 563static const struct isl7998x_mode *isl7998x_norm_to_mode(v4l2_std_id norm)564{565	unsigned int i;566 567	for (i = 0; i < ARRAY_SIZE(isl7998x_std_res); i++)568		if (isl7998x_std_res[i].norm & norm)569			break;570	/* Use NTSC default resolution during standard detection */571	if (i == ARRAY_SIZE(isl7998x_std_res))572		return &supported_modes[1];573 574	return isl7998x_std_res[i].mode;575}576 577static int isl7998x_get_nr_inputs(struct device_node *of_node)578{579	struct device_node *port;580	unsigned int inputs = 0;581	unsigned int i;582 583	if (of_graph_get_endpoint_count(of_node) > ISL7998X_NUM_PADS)584		return -EINVAL;585 586	/*587	 * The driver does not provide means to remap the input ports. It588	 * always configures input ports to start from VID1. Ensure that the589	 * device tree is correct.590	 */591	for (i = ISL7998X_PAD_VIN1; i <= ISL7998X_PAD_VIN4; i++) {592		port = of_graph_get_port_by_id(of_node, i);593		if (!port)594			continue;595 596		inputs |= BIT(i);597		of_node_put(port);598	}599 600	switch (inputs) {601	case BIT(ISL7998X_PAD_VIN1):602		return 1;603	case BIT(ISL7998X_PAD_VIN1) | BIT(ISL7998X_PAD_VIN2):604		return 2;605	case BIT(ISL7998X_PAD_VIN1) | BIT(ISL7998X_PAD_VIN2) |606	     BIT(ISL7998X_PAD_VIN3) | BIT(ISL7998X_PAD_VIN4):607		return 4;608	default:609		return -EINVAL;610	}611}612 613static int isl7998x_wait_power_on(struct isl7998x *isl7998x)614{615	struct device *dev = isl7998x->subdev.dev;616	u32 chip_id;617	int ret;618	int err;619 620	ret = read_poll_timeout(regmap_read, err, !err, 2000, 20000, false,621				isl7998x->regmap,622				ISL7998X_REG_P0_PRODUCT_ID_CODE, &chip_id);623	if (ret) {624		dev_err(dev, "timeout while waiting for ISL7998X\n");625		return ret;626	}627 628	dev_dbg(dev, "Found ISL799%x\n", chip_id);629 630	return ret;631}632 633static int isl7998x_set_standard(struct isl7998x *isl7998x, v4l2_std_id norm)634{635	const struct isl7998x_mode *mode = isl7998x_norm_to_mode(norm);636	unsigned int val = isl7998x_norm_to_val(norm);637	unsigned int width = mode->width;638	unsigned int i;639	int ret;640 641	for (i = 0; i < ISL7998X_INPUTS; i++) {642		ret = regmap_write_bits(isl7998x->regmap,643					ISL7998X_REG_PX_DEC_SDT(i + 1),644					ISL7998X_REG_PX_DEC_SDT_STANDARD,645					val);646		if (ret)647			return ret;648	}649 650	ret = regmap_write(isl7998x->regmap,651			   ISL7998X_REG_P5_LI_ENGINE_LINE_CTL,652			   0x20 | ((width >> 7) & 0x1f));653	if (ret)654		return ret;655 656	ret = regmap_write(isl7998x->regmap,657			   ISL7998X_REG_P5_LI_ENGINE_PIC_WIDTH,658			   (width << 1) & 0xff);659	if (ret)660		return ret;661 662	return 0;663}664 665static int isl7998x_init(struct isl7998x *isl7998x)666{667	const unsigned int lanes = isl7998x->nr_mipi_lanes;668	static const u32 isl7998x_video_in_chan_map[] = { 0x00, 0x11, 0x02, 0x02 };669	const struct reg_sequence isl7998x_init_seq_custom[] = {670		{ ISL7998X_REG_P0_VIDEO_IN_CHAN_CTL,671		  isl7998x_video_in_chan_map[isl7998x->nr_inputs - 1] },672		{ ISL7998X_REG_P0_CLK_CTL_4,673		  (lanes == 1) ? 0x40 : 0x41 },674		{ ISL7998X_REG_P5_LI_ENGINE_CTL,675		  (lanes == 1) ? 0x01 : 0x02 },676	};677	struct device *dev = isl7998x->subdev.dev;678	struct regmap *regmap = isl7998x->regmap;679	int ret;680 681	dev_dbg(dev, "configuring %d lanes for %d inputs (norm %s)\n",682		isl7998x->nr_mipi_lanes, isl7998x->nr_inputs,683		v4l2_norm_to_name(isl7998x->norm));684 685	ret = regmap_register_patch(regmap, isl7998x_init_seq_1,686				    ARRAY_SIZE(isl7998x_init_seq_1));687	if (ret)688		return ret;689 690	mutex_lock(&isl7998x->lock);691	ret = isl7998x_set_standard(isl7998x, isl7998x->norm);692	mutex_unlock(&isl7998x->lock);693	if (ret)694		return ret;695 696	ret = regmap_register_patch(regmap, isl7998x_init_seq_custom,697				    ARRAY_SIZE(isl7998x_init_seq_custom));698	if (ret)699		return ret;700 701	return regmap_register_patch(regmap, isl7998x_init_seq_2,702				     ARRAY_SIZE(isl7998x_init_seq_2));703}704 705static int isl7998x_set_test_pattern(struct isl7998x *isl7998x)706{707	const struct reg_sequence isl7998x_init_seq_tpg_off[] = {708		{ ISL7998X_REG_P5_LI_ENGINE_TP_GEN_CTL, 0 },709		{ ISL7998X_REG_P5_LI_ENGINE_CTL_2, 0 }710	};711	const struct reg_sequence isl7998x_init_seq_tpg_on[] = {712		{ ISL7998X_REG_P5_TP_GEN_BAR_PATTERN,713		  isl7998x->test_pattern_bars << 6 },714		{ ISL7998X_REG_P5_LI_ENGINE_CTL_2,715		  isl7998x->norm & V4L2_STD_PAL ? BIT(2) : 0 },716		{ ISL7998X_REG_P5_LI_ENGINE_TP_GEN_CTL,717		  (isl7998x->test_pattern_chans << 4) |718		  (isl7998x->test_pattern_color << 2) }719	};720	struct device *dev = isl7998x->subdev.dev;721	struct regmap *regmap = isl7998x->regmap;722	int ret;723 724	if (pm_runtime_get_if_in_use(dev) <= 0)725		return 0;726 727	if (isl7998x->test_pattern != 0) {728		dev_dbg(dev, "enabling test pattern: channels 0x%x, %s, %s\n",729			isl7998x->test_pattern_chans,730			isl7998x_test_pattern_bars[isl7998x->test_pattern_bars],731			isl7998x_test_pattern_colors[isl7998x->test_pattern_color]);732		ret = regmap_register_patch(regmap, isl7998x_init_seq_tpg_on,733					    ARRAY_SIZE(isl7998x_init_seq_tpg_on));734	} else {735		ret = regmap_register_patch(regmap, isl7998x_init_seq_tpg_off,736					    ARRAY_SIZE(isl7998x_init_seq_tpg_off));737	}738 739	pm_runtime_put(dev);740 741	return ret;742}743 744#ifdef CONFIG_VIDEO_ADV_DEBUG745static int isl7998x_g_register(struct v4l2_subdev *sd,746			       struct v4l2_dbg_register *reg)747{748	struct isl7998x *isl7998x = sd_to_isl7998x(sd);749	int ret;750	u32 val;751 752	ret = regmap_read(isl7998x->regmap, reg->reg, &val);753	if (ret)754		return ret;755 756	reg->size = 1;757	reg->val = val;758 759	return 0;760}761 762static int isl7998x_s_register(struct v4l2_subdev *sd,763			       const struct v4l2_dbg_register *reg)764{765	struct isl7998x *isl7998x = sd_to_isl7998x(sd);766 767	return regmap_write(isl7998x->regmap, reg->reg, reg->val);768}769#endif770 771static int isl7998x_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm)772{773	struct isl7998x *isl7998x = sd_to_isl7998x(sd);774 775	mutex_lock(&isl7998x->lock);776	*norm = isl7998x->norm;777	mutex_unlock(&isl7998x->lock);778 779	return 0;780}781 782static int isl7998x_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)783{784	struct isl7998x *isl7998x = sd_to_isl7998x(sd);785	struct i2c_client *client = v4l2_get_subdevdata(sd);786	struct device *dev = &client->dev;787	int ret = 0;788 789	mutex_lock(&isl7998x->lock);790	if (isl7998x->enabled) {791		ret = -EBUSY;792		mutex_unlock(&isl7998x->lock);793		return ret;794	}795	isl7998x->norm = norm;796	mutex_unlock(&isl7998x->lock);797 798	if (pm_runtime_get_if_in_use(dev) <= 0)799		return ret;800 801	ret = isl7998x_set_standard(isl7998x, norm);802 803	pm_runtime_put(dev);804 805	return ret;806}807 808static int isl7998x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)809{810	struct isl7998x *isl7998x = sd_to_isl7998x(sd);811	struct i2c_client *client = v4l2_get_subdevdata(sd);812	struct device *dev = &client->dev;813	unsigned int std_id[ISL7998X_INPUTS];814	unsigned int i;815	int ret;816	u32 reg;817 818	ret = pm_runtime_resume_and_get(dev);819	if (ret)820		return ret;821 822	dev_dbg(dev, "starting video standard detection\n");823 824	mutex_lock(&isl7998x->lock);825	if (isl7998x->enabled) {826		ret = -EBUSY;827		goto out_unlock;828	}829 830	ret = isl7998x_set_standard(isl7998x, V4L2_STD_UNKNOWN);831	if (ret)832		goto out_unlock;833 834	for (i = 0; i < ISL7998X_INPUTS; i++) {835		ret = regmap_write(isl7998x->regmap,836				   ISL7998X_REG_PX_DEC_SDTR(i + 1),837				   ISL7998X_REG_PX_DEC_SDTR_ATSTART);838		if (ret)839			goto out_reset_std;840	}841 842	for (i = 0; i < ISL7998X_INPUTS; i++) {843		ret = regmap_read_poll_timeout(isl7998x->regmap,844					       ISL7998X_REG_PX_DEC_SDT(i + 1),845					       reg,846					       !(reg & ISL7998X_REG_PX_DEC_SDT_DET),847					       2000, 500 * USEC_PER_MSEC);848		if (ret)849			goto out_reset_std;850		std_id[i] = FIELD_GET(ISL7998X_REG_PX_DEC_SDT_NOW, reg);851	}852 853	/*854	 * According to Renesas FAE, all input cameras must have the855	 * same standard on this chip.856	 */857	for (i = 0; i < isl7998x->nr_inputs; i++) {858		dev_dbg(dev, "input %d: detected %s\n",859			i, v4l2_norm_to_name(isl7998x_std_res[std_id[i]].norm));860		if (std_id[0] != std_id[i])861			dev_warn(dev,862				 "incompatible standards: %s on input %d (expected %s)\n",863				 v4l2_norm_to_name(isl7998x_std_res[std_id[i]].norm), i,864				 v4l2_norm_to_name(isl7998x_std_res[std_id[0]].norm));865	}866 867	*std = isl7998x_std_res[std_id[0]].norm;868 869out_reset_std:870	isl7998x_set_standard(isl7998x, isl7998x->norm);871out_unlock:872	mutex_unlock(&isl7998x->lock);873	pm_runtime_put(dev);874 875	return ret;876}877 878static int isl7998x_g_tvnorms(struct v4l2_subdev *sd, v4l2_std_id *std)879{880	*std = V4L2_STD_ALL;881 882	return 0;883}884 885static int isl7998x_g_input_status(struct v4l2_subdev *sd, u32 *status)886{887	struct isl7998x *isl7998x = sd_to_isl7998x(sd);888	struct i2c_client *client = v4l2_get_subdevdata(sd);889	struct device *dev = &client->dev;890	unsigned int i;891	int ret = 0;892	u32 reg;893 894	if (!pm_runtime_active(dev)) {895		*status |= V4L2_IN_ST_NO_POWER;896		return 0;897	}898 899	for (i = 0; i < isl7998x->nr_inputs; i++) {900		ret = regmap_read(isl7998x->regmap,901				  ISL7998X_REG_PX_DEC_STATUS_1(i + 1), &reg);902		if (!ret) {903			if (reg & ISL7998X_REG_PX_DEC_STATUS_1_VDLOSS)904				*status |= V4L2_IN_ST_NO_SIGNAL;905			if (!(reg & ISL7998X_REG_PX_DEC_STATUS_1_HLOCK))906				*status |= V4L2_IN_ST_NO_H_LOCK;907			if (!(reg & ISL7998X_REG_PX_DEC_STATUS_1_VLOCK))908				*status |= V4L2_IN_ST_NO_V_LOCK;909		}910	}911 912	return ret;913}914 915static int isl7998x_s_stream(struct v4l2_subdev *sd, int enable)916{917	struct isl7998x *isl7998x = sd_to_isl7998x(sd);918	struct i2c_client *client = v4l2_get_subdevdata(sd);919	struct device *dev = &client->dev;920	int ret = 0;921	u32 reg;922 923	dev_dbg(dev, "stream %s\n", enable ? "ON" : "OFF");924 925	mutex_lock(&isl7998x->lock);926	if (isl7998x->enabled == enable)927		goto out;928	isl7998x->enabled = enable;929 930	if (enable) {931		ret = isl7998x_set_test_pattern(isl7998x);932		if (ret)933			goto out;934	}935 936	regmap_read(isl7998x->regmap,937		    ISL7998X_REG_P5_LI_ENGINE_CTL, &reg);938	if (enable)939		reg &= ~BIT(7);940	else941		reg |= BIT(7);942	ret = regmap_write(isl7998x->regmap,943			   ISL7998X_REG_P5_LI_ENGINE_CTL, reg);944 945out:946	mutex_unlock(&isl7998x->lock);947 948	return ret;949}950 951static int isl7998x_pre_streamon(struct v4l2_subdev *sd, u32 flags)952{953	struct i2c_client *client = v4l2_get_subdevdata(sd);954	struct device *dev = &client->dev;955 956	return pm_runtime_resume_and_get(dev);957}958 959static int isl7998x_post_streamoff(struct v4l2_subdev *sd)960{961	struct i2c_client *client = v4l2_get_subdevdata(sd);962	struct device *dev = &client->dev;963 964	pm_runtime_put(dev);965 966	return 0;967}968 969static int isl7998x_enum_mbus_code(struct v4l2_subdev *sd,970				   struct v4l2_subdev_state *sd_state,971				   struct v4l2_subdev_mbus_code_enum *code)972{973	if (code->index >= ARRAY_SIZE(isl7998x_colour_fmts))974		return -EINVAL;975 976	code->code = isl7998x_colour_fmts[code->index].code;977 978	return 0;979}980 981static int isl7998x_enum_frame_size(struct v4l2_subdev *sd,982				    struct v4l2_subdev_state *sd_state,983				    struct v4l2_subdev_frame_size_enum *fse)984{985	if (fse->index >= ARRAY_SIZE(supported_modes))986		return -EINVAL;987 988	if (fse->code != isl7998x_colour_fmts[0].code)989		return -EINVAL;990 991	fse->min_width = supported_modes[fse->index].width;992	fse->max_width = fse->min_width;993	fse->min_height = supported_modes[fse->index].height;994	fse->max_height = fse->min_height;995 996	return 0;997}998 999static int isl7998x_get_fmt(struct v4l2_subdev *sd,1000			    struct v4l2_subdev_state *sd_state,1001			    struct v4l2_subdev_format *format)1002{1003	struct isl7998x *isl7998x = sd_to_isl7998x(sd);1004	struct v4l2_mbus_framefmt *mf = &format->format;1005	const struct isl7998x_mode *mode;1006 1007	mutex_lock(&isl7998x->lock);1008 1009	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {1010		format->format = *v4l2_subdev_state_get_format(sd_state,1011							       format->pad);1012		goto out;1013	}1014 1015	mode = isl7998x_norm_to_mode(isl7998x->norm);1016 1017	mf->width	= mode->width;1018	mf->height	= mode->height;1019	mf->code	= isl7998x->fmt->code;1020	mf->field	= mode->field;1021	mf->colorspace	= 0;1022 1023out:1024	mutex_unlock(&isl7998x->lock);1025 1026	return 0;1027}1028 1029static int isl7998x_set_fmt(struct v4l2_subdev *sd,1030			    struct v4l2_subdev_state *sd_state,1031			    struct v4l2_subdev_format *format)1032{1033	struct isl7998x *isl7998x = sd_to_isl7998x(sd);1034	struct v4l2_mbus_framefmt *mf = &format->format;1035	const struct isl7998x_mode *mode;1036 1037	mutex_lock(&isl7998x->lock);1038 1039	mode = isl7998x_norm_to_mode(isl7998x->norm);1040 1041	mf->width = mode->width;1042	mf->height = mode->height;1043	mf->code = isl7998x->fmt->code;1044	mf->field = mode->field;1045 1046	if (format->which == V4L2_SUBDEV_FORMAT_TRY)1047		*v4l2_subdev_state_get_format(sd_state, format->pad) = format->format;1048 1049	mutex_unlock(&isl7998x->lock);1050 1051	return 0;1052}1053 1054static int isl7998x_set_ctrl(struct v4l2_ctrl *ctrl)1055{1056	struct isl7998x *isl7998x = container_of(ctrl->handler,1057						 struct isl7998x, ctrl_handler);1058	int ret = 0;1059 1060	switch (ctrl->id) {1061	case V4L2_CID_TEST_PATTERN_BARS:1062		mutex_lock(&isl7998x->lock);1063		isl7998x->test_pattern_bars = ctrl->val & 0x3;1064		ret = isl7998x_set_test_pattern(isl7998x);1065		mutex_unlock(&isl7998x->lock);1066		break;1067	case V4L2_CID_TEST_PATTERN_CHANNELS:1068		mutex_lock(&isl7998x->lock);1069		isl7998x->test_pattern_chans = ctrl->val & 0xf;1070		ret = isl7998x_set_test_pattern(isl7998x);1071		mutex_unlock(&isl7998x->lock);1072		break;1073	case V4L2_CID_TEST_PATTERN_COLOR:1074		mutex_lock(&isl7998x->lock);1075		isl7998x->test_pattern_color = ctrl->val & 0x3;1076		ret = isl7998x_set_test_pattern(isl7998x);1077		mutex_unlock(&isl7998x->lock);1078		break;1079	case V4L2_CID_TEST_PATTERN:1080		mutex_lock(&isl7998x->lock);1081		isl7998x->test_pattern = ctrl->val;1082		ret = isl7998x_set_test_pattern(isl7998x);1083		mutex_unlock(&isl7998x->lock);1084		break;1085	}1086 1087	return ret;1088}1089 1090static const struct v4l2_subdev_core_ops isl7998x_subdev_core_ops = {1091#ifdef CONFIG_VIDEO_ADV_DEBUG1092	.g_register	= isl7998x_g_register,1093	.s_register	= isl7998x_s_register,1094#endif1095};1096 1097static const struct v4l2_subdev_video_ops isl7998x_subdev_video_ops = {1098	.g_std		= isl7998x_g_std,1099	.s_std		= isl7998x_s_std,1100	.querystd	= isl7998x_querystd,1101	.g_tvnorms	= isl7998x_g_tvnorms,1102	.g_input_status	= isl7998x_g_input_status,1103	.s_stream	= isl7998x_s_stream,1104	.pre_streamon	= isl7998x_pre_streamon,1105	.post_streamoff	= isl7998x_post_streamoff,1106};1107 1108static const struct v4l2_subdev_pad_ops isl7998x_subdev_pad_ops = {1109	.enum_mbus_code		= isl7998x_enum_mbus_code,1110	.enum_frame_size	= isl7998x_enum_frame_size,1111	.get_fmt		= isl7998x_get_fmt,1112	.set_fmt		= isl7998x_set_fmt,1113};1114 1115static const struct v4l2_subdev_ops isl7998x_subdev_ops = {1116	.core		= &isl7998x_subdev_core_ops,1117	.video		= &isl7998x_subdev_video_ops,1118	.pad		= &isl7998x_subdev_pad_ops,1119};1120 1121static const struct media_entity_operations isl7998x_entity_ops = {1122	.link_validate = v4l2_subdev_link_validate,1123};1124 1125static const struct v4l2_ctrl_ops isl7998x_ctrl_ops = {1126	.s_ctrl			= isl7998x_set_ctrl,1127};1128 1129static const struct v4l2_ctrl_config isl7998x_ctrls[] = {1130	{1131		.ops		= &isl7998x_ctrl_ops,1132		.id		= V4L2_CID_TEST_PATTERN_BARS,1133		.type		= V4L2_CTRL_TYPE_MENU,1134		.name		= "Test Pattern Bars",1135		.max		= ARRAY_SIZE(isl7998x_test_pattern_bars) - 1,1136		.def		= 0,1137		.qmenu		= isl7998x_test_pattern_bars,1138	}, {1139		.ops		= &isl7998x_ctrl_ops,1140		.id		= V4L2_CID_TEST_PATTERN_CHANNELS,1141		.type		= V4L2_CTRL_TYPE_INTEGER,1142		.name		= "Test Pattern Channels",1143		.min		= 0,1144		.max		= 0xf,1145		.step		= 1,1146		.def		= 0xf,1147		.flags		= 0,1148	}, {1149		.ops		= &isl7998x_ctrl_ops,1150		.id		= V4L2_CID_TEST_PATTERN_COLOR,1151		.type		= V4L2_CTRL_TYPE_MENU,1152		.name		= "Test Pattern Color",1153		.max		= ARRAY_SIZE(isl7998x_test_pattern_colors) - 1,1154		.def		= 0,1155		.qmenu		= isl7998x_test_pattern_colors,1156	},1157};1158 1159#define ISL7998X_REG_DECODER_ACA_READABLE_RANGE(page)			\1160	/* Decoder range */						\1161	regmap_reg_range(ISL7998X_REG_PX_DEC_INPUT_FMT(page),		\1162			 ISL7998X_REG_PX_DEC_HS_DELAY_CTL(page)),	\1163	regmap_reg_range(ISL7998X_REG_PX_DEC_ANCTL(page),		\1164			 ISL7998X_REG_PX_DEC_CSC_CTL(page)),		\1165	regmap_reg_range(ISL7998X_REG_PX_DEC_BRIGHT(page),		\1166			 ISL7998X_REG_PX_DEC_HUE(page)),		\1167	regmap_reg_range(ISL7998X_REG_PX_DEC_VERT_PEAK(page),		\1168			 ISL7998X_REG_PX_DEC_CORING(page)),		\1169	regmap_reg_range(ISL7998X_REG_PX_DEC_SDT(page),			\1170			 ISL7998X_REG_PX_DEC_SDTR(page)),		\1171	regmap_reg_range(ISL7998X_REG_PX_DEC_CLMPG(page),		\1172			 ISL7998X_REG_PX_DEC_DATA_CONV(page)),		\1173	regmap_reg_range(ISL7998X_REG_PX_DEC_INTERNAL_TEST(page),	\1174			 ISL7998X_REG_PX_DEC_INTERNAL_TEST(page)),	\1175	regmap_reg_range(ISL7998X_REG_PX_DEC_H_DELAY_CTL(page),		\1176			 ISL7998X_REG_PX_DEC_H_DELAY_II_LOW(page)),	\1177	/* ACA range */							\1178	regmap_reg_range(ISL7998X_REG_PX_ACA_CTL_1(page),		\1179			 ISL7998X_REG_PX_ACA_HIST_WIN_V_SZ2(page)),	\1180	regmap_reg_range(ISL7998X_REG_PX_ACA_Y_AVG(page),		\1181			 ISL7998X_REG_PX_ACA_CTL_4(page)),		\1182	regmap_reg_range(ISL7998X_REG_PX_ACA_FLEX_WIN_HIST(page),	\1183			 ISL7998X_REG_PX_ACA_XFER_HIST_HOST(page)),	\1184	regmap_reg_range(ISL7998X_REG_PX_DEC_PAGE(page),		\1185			 ISL7998X_REG_PX_DEC_PAGE(page))1186 1187#define ISL7998X_REG_DECODER_ACA_WRITEABLE_RANGE(page)			\1188	/* Decoder range */						\1189	regmap_reg_range(ISL7998X_REG_PX_DEC_INPUT_FMT(page),		\1190			 ISL7998X_REG_PX_DEC_INPUT_FMT(page)),		\1191	regmap_reg_range(ISL7998X_REG_PX_DEC_HS_DELAY_CTL(page),	\1192			 ISL7998X_REG_PX_DEC_HS_DELAY_CTL(page)),	\1193	regmap_reg_range(ISL7998X_REG_PX_DEC_ANCTL(page),		\1194			 ISL7998X_REG_PX_DEC_CSC_CTL(page)),		\1195	regmap_reg_range(ISL7998X_REG_PX_DEC_BRIGHT(page),		\1196			 ISL7998X_REG_PX_DEC_HUE(page)),		\1197	regmap_reg_range(ISL7998X_REG_PX_DEC_VERT_PEAK(page),		\1198			 ISL7998X_REG_PX_DEC_CORING(page)),		\1199	regmap_reg_range(ISL7998X_REG_PX_DEC_SDT(page),			\1200			 ISL7998X_REG_PX_DEC_SDTR(page)),		\1201	regmap_reg_range(ISL7998X_REG_PX_DEC_CLMPG(page),		\1202			 ISL7998X_REG_PX_DEC_MISC3(page)),		\1203	regmap_reg_range(ISL7998X_REG_PX_DEC_CLMD(page),		\1204			 ISL7998X_REG_PX_DEC_DATA_CONV(page)),		\1205	regmap_reg_range(ISL7998X_REG_PX_DEC_INTERNAL_TEST(page),	\1206			 ISL7998X_REG_PX_DEC_INTERNAL_TEST(page)),	\1207	regmap_reg_range(ISL7998X_REG_PX_DEC_H_DELAY_CTL(page),		\1208			 ISL7998X_REG_PX_DEC_H_DELAY_II_LOW(page)),	\1209	/* ACA range */							\1210	regmap_reg_range(ISL7998X_REG_PX_ACA_CTL_1(page),		\1211			 ISL7998X_REG_PX_ACA_HIST_WIN_V_SZ2(page)),	\1212	regmap_reg_range(ISL7998X_REG_PX_ACA_CTL_2(page),		\1213			 ISL7998X_REG_PX_ACA_CTL_4(page)),		\1214	regmap_reg_range(ISL7998X_REG_PX_ACA_FLEX_WIN_HIST(page),	\1215			 ISL7998X_REG_PX_ACA_HIST_DATA_LO(page)),	\1216	regmap_reg_range(ISL7998X_REG_PX_ACA_XFER_HIST_HOST(page),	\1217			 ISL7998X_REG_PX_ACA_XFER_HIST_HOST(page)),	\1218	regmap_reg_range(ISL7998X_REG_PX_DEC_PAGE(page),		\1219			 ISL7998X_REG_PX_DEC_PAGE(page))1220 1221#define ISL7998X_REG_DECODER_ACA_VOLATILE_RANGE(page)			\1222	/* Decoder range */						\1223	regmap_reg_range(ISL7998X_REG_PX_DEC_STATUS_1(page),		\1224			 ISL7998X_REG_PX_DEC_STATUS_1(page)),		\1225	regmap_reg_range(ISL7998X_REG_PX_DEC_SDT(page),			\1226			 ISL7998X_REG_PX_DEC_SDT(page)),		\1227	regmap_reg_range(ISL7998X_REG_PX_DEC_MVSN(page),		\1228			 ISL7998X_REG_PX_DEC_HFREF(page)),		\1229	/* ACA range */							\1230	regmap_reg_range(ISL7998X_REG_PX_ACA_Y_AVG(page),		\1231			 ISL7998X_REG_PX_ACA_Y_HIGH(page)),		\1232	regmap_reg_range(ISL7998X_REG_PX_ACA_HIST_DATA_LO(page),	\1233			 ISL7998X_REG_PX_ACA_FLEX_WIN_CR_CLR(page))1234 1235static const struct regmap_range isl7998x_readable_ranges[] = {1236	regmap_reg_range(ISL7998X_REG_P0_PRODUCT_ID_CODE,1237			 ISL7998X_REG_P0_IRQ_SYNC_CTL),1238	regmap_reg_range(ISL7998X_REG_P0_INTERRUPT_STATUS,1239			 ISL7998X_REG_P0_CLOCK_DELAY),1240	regmap_reg_range(ISL7998X_REG_PX_DEC_PAGE(0),1241			 ISL7998X_REG_PX_DEC_PAGE(0)),1242 1243	ISL7998X_REG_DECODER_ACA_READABLE_RANGE(1),1244	ISL7998X_REG_DECODER_ACA_READABLE_RANGE(2),1245	ISL7998X_REG_DECODER_ACA_READABLE_RANGE(3),1246	ISL7998X_REG_DECODER_ACA_READABLE_RANGE(4),1247 1248	regmap_reg_range(ISL7998X_REG_P5_LI_ENGINE_CTL,1249			 ISL7998X_REG_P5_MIPI_SP_HS_TRL_CTL),1250	regmap_reg_range(ISL7998X_REG_P5_FIFO_THRSH_CNT_1,1251			 ISL7998X_REG_P5_PLL_ANA),1252	regmap_reg_range(ISL7998X_REG_P5_TOTAL_PF_LINE_CNT_1,1253			 ISL7998X_REG_P5_HIST_LINE_CNT_2),1254	regmap_reg_range(ISL7998X_REG_PX_DEC_PAGE(5),1255			 ISL7998X_REG_PX_DEC_PAGE(5)),1256};1257 1258static const struct regmap_range isl7998x_writeable_ranges[] = {1259	regmap_reg_range(ISL7998X_REG_P0_SW_RESET_CTL,1260			 ISL7998X_REG_P0_IRQ_SYNC_CTL),1261	regmap_reg_range(ISL7998X_REG_P0_CHAN_1_IRQ,1262			 ISL7998X_REG_P0_SHORT_DIAG_IRQ_EN),1263	regmap_reg_range(ISL7998X_REG_P0_CLOCK_DELAY,1264			 ISL7998X_REG_P0_CLOCK_DELAY),1265	regmap_reg_range(ISL7998X_REG_PX_DEC_PAGE(0),1266			 ISL7998X_REG_PX_DEC_PAGE(0)),1267 1268	ISL7998X_REG_DECODER_ACA_WRITEABLE_RANGE(1),1269	ISL7998X_REG_DECODER_ACA_WRITEABLE_RANGE(2),1270	ISL7998X_REG_DECODER_ACA_WRITEABLE_RANGE(3),1271	ISL7998X_REG_DECODER_ACA_WRITEABLE_RANGE(4),1272 1273	regmap_reg_range(ISL7998X_REG_P5_LI_ENGINE_CTL,1274			 ISL7998X_REG_P5_ESC_MODE_TIME_CTL),1275	regmap_reg_range(ISL7998X_REG_P5_MIPI_SP_HS_TRL_CTL,1276			 ISL7998X_REG_P5_PLL_ANA),1277	regmap_reg_range(ISL7998X_REG_P5_TOTAL_PF_LINE_CNT_1,1278			 ISL7998X_REG_P5_HIST_LINE_CNT_2),1279	regmap_reg_range(ISL7998X_REG_PX_DEC_PAGE(5),1280			 ISL7998X_REG_PX_DEC_PAGE(5)),1281 1282	ISL7998X_REG_DECODER_ACA_WRITEABLE_RANGE(0xf),1283};1284 1285static const struct regmap_range isl7998x_volatile_ranges[] = {1286	/* Product id code register is used to check availability */1287	regmap_reg_range(ISL7998X_REG_P0_PRODUCT_ID_CODE,1288			 ISL7998X_REG_P0_PRODUCT_ID_CODE),1289	regmap_reg_range(ISL7998X_REG_P0_MPP1_SYNC_CTL,1290			 ISL7998X_REG_P0_IRQ_SYNC_CTL),1291	regmap_reg_range(ISL7998X_REG_P0_INTERRUPT_STATUS,1292			 ISL7998X_REG_P0_INTERRUPT_STATUS),1293	regmap_reg_range(ISL7998X_REG_P0_CHAN_1_STATUS,1294			 ISL7998X_REG_P0_SHORT_DIAG_STATUS),1295 1296	ISL7998X_REG_DECODER_ACA_VOLATILE_RANGE(1),1297	ISL7998X_REG_DECODER_ACA_VOLATILE_RANGE(2),1298	ISL7998X_REG_DECODER_ACA_VOLATILE_RANGE(3),1299	ISL7998X_REG_DECODER_ACA_VOLATILE_RANGE(4),1300 1301	regmap_reg_range(ISL7998X_REG_P5_AUTO_TEST_ERR_DET,1302			 ISL7998X_REG_P5_PIC_HEIGHT_LOW),1303};1304 1305static const struct regmap_access_table isl7998x_readable_table = {1306	.yes_ranges = isl7998x_readable_ranges,1307	.n_yes_ranges = ARRAY_SIZE(isl7998x_readable_ranges),1308};1309 1310static const struct regmap_access_table isl7998x_writeable_table = {1311	.yes_ranges = isl7998x_writeable_ranges,1312	.n_yes_ranges = ARRAY_SIZE(isl7998x_writeable_ranges),1313};1314 1315static const struct regmap_access_table isl7998x_volatile_table = {1316	.yes_ranges = isl7998x_volatile_ranges,1317	.n_yes_ranges = ARRAY_SIZE(isl7998x_volatile_ranges),1318};1319 1320static const struct regmap_range_cfg isl7998x_ranges[] = {1321	{1322		.range_min	= ISL7998X_REG_PN_BASE(0),1323		.range_max	= ISL7998X_REG_PX_ACA_XFER_HIST_HOST(0xf),1324		.selector_reg	= ISL7998X_REG_PX_DEC_PAGE(0),1325		.selector_mask	= ISL7998X_REG_PX_DEC_PAGE_MASK,1326		.window_start	= 0,1327		.window_len	= 256,1328	}1329};1330 1331static const struct regmap_config isl7998x_regmap = {1332	.reg_bits	= 8,1333	.val_bits	= 8,1334	.max_register	= ISL7998X_REG_PX_ACA_XFER_HIST_HOST(0xf),1335	.ranges		= isl7998x_ranges,1336	.num_ranges	= ARRAY_SIZE(isl7998x_ranges),1337	.rd_table	= &isl7998x_readable_table,1338	.wr_table	= &isl7998x_writeable_table,1339	.volatile_table	= &isl7998x_volatile_table,1340	.cache_type	= REGCACHE_MAPLE,1341};1342 1343static int isl7998x_mc_init(struct isl7998x *isl7998x)1344{1345	unsigned int i;1346 1347	isl7998x->subdev.entity.ops = &isl7998x_entity_ops;1348	isl7998x->subdev.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;1349 1350	isl7998x->pads[ISL7998X_PAD_OUT].flags = MEDIA_PAD_FL_SOURCE;1351	for (i = ISL7998X_PAD_VIN1; i < ISL7998X_NUM_PADS; i++)1352		isl7998x->pads[i].flags = MEDIA_PAD_FL_SINK;1353 1354	return media_entity_pads_init(&isl7998x->subdev.entity,1355				      ISL7998X_NUM_PADS,1356				      isl7998x->pads);1357}1358 1359static int get_link_freq_menu_index(unsigned int lanes,1360				    unsigned int inputs)1361{1362	int ret = -EINVAL;1363 1364	switch (lanes) {1365	case 1:1366		if (inputs == 1)1367			ret = 0;1368		if (inputs == 2)1369			ret = 1;1370		if (inputs == 4)1371			ret = 2;1372		break;1373	case 2:1374		if (inputs == 2)1375			ret = 0;1376		if (inputs == 4)1377			ret = 1;1378		break;1379	default:1380		break;1381	}1382 1383	return ret;1384}1385 1386static void isl7998x_remove_controls(struct isl7998x *isl7998x)1387{1388	v4l2_ctrl_handler_free(&isl7998x->ctrl_handler);1389	mutex_destroy(&isl7998x->ctrl_mutex);1390}1391 1392static int isl7998x_init_controls(struct isl7998x *isl7998x)1393{1394	struct v4l2_subdev *sd = &isl7998x->subdev;1395	int link_freq_index;1396	unsigned int i;1397	int ret;1398 1399	ret = v4l2_ctrl_handler_init(&isl7998x->ctrl_handler,1400				     2 + ARRAY_SIZE(isl7998x_ctrls));1401	if (ret)1402		return ret;1403 1404	mutex_init(&isl7998x->ctrl_mutex);1405	isl7998x->ctrl_handler.lock = &isl7998x->ctrl_mutex;1406	link_freq_index = get_link_freq_menu_index(isl7998x->nr_mipi_lanes,1407						   isl7998x->nr_inputs);1408	if (link_freq_index < 0 ||1409	    link_freq_index >= ARRAY_SIZE(link_freq_menu_items)) {1410		dev_err(sd->dev,1411			"failed to find MIPI link freq: %d lanes, %d inputs\n",1412			isl7998x->nr_mipi_lanes, isl7998x->nr_inputs);1413		ret = -EINVAL;1414		goto err;1415	}1416 1417	isl7998x->link_freq = v4l2_ctrl_new_int_menu(&isl7998x->ctrl_handler,1418						     &isl7998x_ctrl_ops,1419						     V4L2_CID_LINK_FREQ,1420						     ARRAY_SIZE(link_freq_menu_items) - 1,1421						     link_freq_index,1422						     link_freq_menu_items);1423	if (isl7998x->link_freq)1424		isl7998x->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;1425 1426	for (i = 0; i < ARRAY_SIZE(isl7998x_ctrls); i++)1427		v4l2_ctrl_new_custom(&isl7998x->ctrl_handler,1428				     &isl7998x_ctrls[i], NULL);1429 1430	v4l2_ctrl_new_std_menu_items(&isl7998x->ctrl_handler,1431				     &isl7998x_ctrl_ops,1432				     V4L2_CID_TEST_PATTERN,1433				     ARRAY_SIZE(isl7998x_test_pattern_menu) - 1,1434				     0, 0, isl7998x_test_pattern_menu);1435 1436	ret = isl7998x->ctrl_handler.error;1437	if (ret)1438		goto err;1439 1440	isl7998x->subdev.ctrl_handler = &isl7998x->ctrl_handler;1441	v4l2_ctrl_handler_setup(&isl7998x->ctrl_handler);1442 1443	return 0;1444 1445err:1446	isl7998x_remove_controls(isl7998x);1447 1448	return ret;1449}1450 1451static int isl7998x_probe(struct i2c_client *client)1452{1453	struct device *dev = &client->dev;1454	struct v4l2_fwnode_endpoint endpoint = {1455		.bus_type = V4L2_MBUS_CSI2_DPHY,1456	};1457	struct fwnode_handle *ep;1458	struct isl7998x *isl7998x;1459	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);1460	int nr_inputs;1461	int ret;1462 1463	ret = i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA);1464	if (!ret) {1465		dev_warn(&adapter->dev,1466			 "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");1467		return -EIO;1468	}1469 1470	isl7998x = devm_kzalloc(dev, sizeof(*isl7998x), GFP_KERNEL);1471	if (!isl7998x)1472		return -ENOMEM;1473 1474	isl7998x->pd_gpio = devm_gpiod_get_optional(dev, "powerdown",1475						    GPIOD_OUT_HIGH);1476	if (IS_ERR(isl7998x->pd_gpio))1477		return dev_err_probe(dev, PTR_ERR(isl7998x->pd_gpio),1478				     "Failed to retrieve/request PD GPIO\n");1479 1480	isl7998x->rstb_gpio = devm_gpiod_get_optional(dev, "reset",1481						      GPIOD_OUT_HIGH);1482	if (IS_ERR(isl7998x->rstb_gpio))1483		return dev_err_probe(dev, PTR_ERR(isl7998x->rstb_gpio),1484				     "Failed to retrieve/request RSTB GPIO\n");1485 1486	isl7998x->regmap = devm_regmap_init_i2c(client, &isl7998x_regmap);1487	if (IS_ERR(isl7998x->regmap))1488		return dev_err_probe(dev, PTR_ERR(isl7998x->regmap),1489				     "Failed to allocate register map\n");1490 1491	ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev),1492					     ISL7998X_PAD_OUT, 0, 0);1493	if (!ep)1494		return dev_err_probe(dev, -EINVAL, "Missing endpoint node\n");1495 1496	ret = v4l2_fwnode_endpoint_parse(ep, &endpoint);1497	fwnode_handle_put(ep);1498	if (ret)1499		return dev_err_probe(dev, ret, "Failed to parse endpoint\n");1500 1501	if (endpoint.bus.mipi_csi2.num_data_lanes == 0 ||1502	    endpoint.bus.mipi_csi2.num_data_lanes > 2)1503		return dev_err_probe(dev, -EINVAL,1504				     "Invalid number of MIPI lanes\n");1505 1506	isl7998x->nr_mipi_lanes = endpoint.bus.mipi_csi2.num_data_lanes;1507 1508	nr_inputs = isl7998x_get_nr_inputs(dev->of_node);1509	if (nr_inputs < 0)1510		return dev_err_probe(dev, nr_inputs,1511				     "Invalid number of input ports\n");1512	isl7998x->nr_inputs = nr_inputs;1513 1514	v4l2_i2c_subdev_init(&isl7998x->subdev, client, &isl7998x_subdev_ops);1515	isl7998x->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;1516 1517	ret = isl7998x_mc_init(isl7998x);1518	if (ret < 0)1519		return ret;1520 1521	isl7998x->fmt = &isl7998x_colour_fmts[0];1522	isl7998x->norm = V4L2_STD_NTSC;1523	isl7998x->enabled = 0;1524 1525	mutex_init(&isl7998x->lock);1526 1527	ret = isl7998x_init_controls(isl7998x);1528	if (ret)1529		goto err_entity_cleanup;1530 1531	ret = v4l2_async_register_subdev(&isl7998x->subdev);1532	if (ret < 0)1533		goto err_controls_cleanup;1534 1535	pm_runtime_enable(dev);1536 1537	return 0;1538 1539err_controls_cleanup:1540	isl7998x_remove_controls(isl7998x);1541err_entity_cleanup:1542	media_entity_cleanup(&isl7998x->subdev.entity);1543 1544	return ret;1545}1546 1547static void isl7998x_remove(struct i2c_client *client)1548{1549	struct isl7998x *isl7998x = i2c_to_isl7998x(client);1550 1551	pm_runtime_disable(&client->dev);1552	v4l2_async_unregister_subdev(&isl7998x->subdev);1553	isl7998x_remove_controls(isl7998x);1554	media_entity_cleanup(&isl7998x->subdev.entity);1555}1556 1557static const struct of_device_id isl7998x_of_match[] = {1558	{ .compatible = "isil,isl79987", },1559	{ /* sentinel */ },1560};1561MODULE_DEVICE_TABLE(of, isl7998x_of_match);1562 1563static const struct i2c_device_id isl7998x_id[] = {1564	{ "isl79987" },1565	{ /* sentinel */ }1566};1567MODULE_DEVICE_TABLE(i2c, isl7998x_id);1568 1569static int __maybe_unused isl7998x_runtime_resume(struct device *dev)1570{1571	struct v4l2_subdev *sd = dev_get_drvdata(dev);1572	struct isl7998x *isl7998x = sd_to_isl7998x(sd);1573	int ret;1574 1575	gpiod_set_value(isl7998x->rstb_gpio, 1);1576	gpiod_set_value(isl7998x->pd_gpio, 0);1577	gpiod_set_value(isl7998x->rstb_gpio, 0);1578 1579	ret = isl7998x_wait_power_on(isl7998x);1580	if (ret)1581		goto err;1582 1583	ret = isl7998x_init(isl7998x);1584	if (ret)1585		goto err;1586 1587	return 0;1588 1589err:1590	gpiod_set_value(isl7998x->pd_gpio, 1);1591 1592	return ret;1593}1594 1595static int __maybe_unused isl7998x_runtime_suspend(struct device *dev)1596{1597	struct v4l2_subdev *sd = dev_get_drvdata(dev);1598	struct isl7998x *isl7998x = sd_to_isl7998x(sd);1599 1600	gpiod_set_value(isl7998x->pd_gpio, 1);1601 1602	return 0;1603}1604 1605static const struct dev_pm_ops isl7998x_pm_ops = {1606	SET_RUNTIME_PM_OPS(isl7998x_runtime_suspend,1607			   isl7998x_runtime_resume,1608			   NULL)1609};1610 1611static struct i2c_driver isl7998x_i2c_driver = {1612	.driver = {1613		.name = "isl7998x",1614		.of_match_table = isl7998x_of_match,1615		.pm = &isl7998x_pm_ops,1616	},1617	.probe		= isl7998x_probe,1618	.remove		= isl7998x_remove,1619	.id_table	= isl7998x_id,1620};1621 1622module_i2c_driver(isl7998x_i2c_driver);1623 1624MODULE_DESCRIPTION("Intersil ISL7998x Analog to MIPI CSI-2/BT656 decoder");1625MODULE_AUTHOR("Marek Vasut <marex@denx.de>");1626MODULE_LICENSE("GPL v2");1627