1// SPDX-License-Identifier: GPL-2.0
2/*
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 on
30 * 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 4
48
49#define ISL7998X_REG(page, reg) (((page) << 8) | (reg))
50
51#define ISL7998X_REG_PN_SIZE 256
52#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 0xf
56#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 0
116#define ISL7998X_REG_PX_DEC_SDT_STANDARD_PAL 1
117#define ISL7998X_REG_PX_DEC_SDT_STANDARD_SECAM 2
118#define ISL7998X_REG_PX_DEC_SDT_STANDARD_NTSC_443 3
119#define ISL7998X_REG_PX_DEC_SDT_STANDARD_PAL_M 4
120#define ISL7998X_REG_PX_DEC_SDT_STANDARD_PAL_CN 5
121#define ISL7998X_REG_PX_DEC_SDT_STANDARD_PAL_60 6
122#define ISL7998X_REG_PX_DEC_SDT_STANDARD_UNKNOWN 7
123#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 frame
411 * 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_PADS
423};
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(sd: 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(np: of_node) > ISL7998X_NUM_PADS)
584 return -EINVAL;
585
586 /*
587 * The driver does not provide means to remap the input ports. It
588 * always configures input ports to start from VID1. Ensure that the
589 * device tree is correct.
590 */
591 for (i = ISL7998X_PAD_VIN1; i <= ISL7998X_PAD_VIN4; i++) {
592 port = of_graph_get_port_by_id(node: of_node, id: i);
593 if (!port)
594 continue;
595
596 inputs |= BIT(i);
597 of_node_put(node: 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(map: 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(map: isl7998x->regmap,
651 ISL7998X_REG_P5_LI_ENGINE_LINE_CTL,
652 val: 0x20 | ((width >> 7) & 0x1f));
653 if (ret)
654 return ret;
655
656 ret = regmap_write(map: isl7998x->regmap,
657 ISL7998X_REG_P5_LI_ENGINE_PIC_WIDTH,
658 val: (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(map: regmap, regs: 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, norm: isl7998x->norm);
692 mutex_unlock(lock: &isl7998x->lock);
693 if (ret)
694 return ret;
695
696 ret = regmap_register_patch(map: regmap, regs: isl7998x_init_seq_custom,
697 ARRAY_SIZE(isl7998x_init_seq_custom));
698 if (ret)
699 return ret;
700
701 return regmap_register_patch(map: regmap, regs: 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(map: regmap, regs: isl7998x_init_seq_tpg_on,
733 ARRAY_SIZE(isl7998x_init_seq_tpg_on));
734 } else {
735 ret = regmap_register_patch(map: regmap, regs: 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_DEBUG
745static 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(map: isl7998x->regmap, reg: reg->reg, val: &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(map: isl7998x->regmap, reg: reg->reg, val: reg->val);
768}
769#endif
770
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(lock: &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(lock: &isl7998x->lock);
793 return ret;
794 }
795 isl7998x->norm = norm;
796 mutex_unlock(lock: &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(map: 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 the
855 * 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, norm: isl7998x->norm);
871out_unlock:
872 mutex_unlock(lock: &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(map: isl7998x->regmap,
901 ISL7998X_REG_PX_DEC_STATUS_1(i + 1), val: &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(map: isl7998x->regmap,
937 ISL7998X_REG_P5_LI_ENGINE_CTL, val: &reg);
938 if (enable)
939 reg &= ~BIT(7);
940 else
941 reg |= BIT(7);
942 ret = regmap_write(map: isl7998x->regmap,
943 ISL7998X_REG_P5_LI_ENGINE_CTL, val: reg);
944
945out:
946 mutex_unlock(lock: &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(norm: 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(lock: &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(norm: 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(lock: &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(lock: &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(lock: &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(lock: &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(lock: &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_DEBUG
1092 .g_register = isl7998x_g_register,
1093 .s_register = isl7998x_s_register,
1094#endif
1095};
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(entity: &isl7998x->subdev.entity,
1355 num_pads: ISL7998X_NUM_PADS,
1356 pads: 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(hdl: &isl7998x->ctrl_handler);
1389 mutex_destroy(lock: &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(lanes: isl7998x->nr_mipi_lanes,
1407 inputs: 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(hdl: &isl7998x->ctrl_handler,
1418 ops: &isl7998x_ctrl_ops,
1419 V4L2_CID_LINK_FREQ,
1420 ARRAY_SIZE(link_freq_menu_items) - 1,
1421 def: link_freq_index,
1422 qmenu_int: 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(hdl: &isl7998x->ctrl_handler,
1428 cfg: &isl7998x_ctrls[i], NULL);
1429
1430 v4l2_ctrl_new_std_menu_items(hdl: &isl7998x->ctrl_handler,
1431 ops: &isl7998x_ctrl_ops,
1432 V4L2_CID_TEST_PATTERN,
1433 ARRAY_SIZE(isl7998x_test_pattern_menu) - 1,
1434 mask: 0, def: 0, qmenu: 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(hdl: &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(adap: 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, size: sizeof(*isl7998x), GFP_KERNEL);
1471 if (!isl7998x)
1472 return -ENOMEM;
1473
1474 isl7998x->pd_gpio = devm_gpiod_get_optional(dev, con_id: "powerdown",
1475 flags: GPIOD_OUT_HIGH);
1476 if (IS_ERR(ptr: isl7998x->pd_gpio))
1477 return dev_err_probe(dev, err: PTR_ERR(ptr: isl7998x->pd_gpio),
1478 fmt: "Failed to retrieve/request PD GPIO\n");
1479
1480 isl7998x->rstb_gpio = devm_gpiod_get_optional(dev, con_id: "reset",
1481 flags: GPIOD_OUT_HIGH);
1482 if (IS_ERR(ptr: isl7998x->rstb_gpio))
1483 return dev_err_probe(dev, err: PTR_ERR(ptr: isl7998x->rstb_gpio),
1484 fmt: "Failed to retrieve/request RSTB GPIO\n");
1485
1486 isl7998x->regmap = devm_regmap_init_i2c(client, &isl7998x_regmap);
1487 if (IS_ERR(ptr: isl7998x->regmap))
1488 return dev_err_probe(dev, err: PTR_ERR(ptr: isl7998x->regmap),
1489 fmt: "Failed to allocate register map\n");
1490
1491 ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev),
1492 port: ISL7998X_PAD_OUT, endpoint: 0, flags: 0);
1493 if (!ep)
1494 return dev_err_probe(dev, err: -EINVAL, fmt: "Missing endpoint node\n");
1495
1496 ret = v4l2_fwnode_endpoint_parse(fwnode: ep, vep: &endpoint);
1497 fwnode_handle_put(fwnode: ep);
1498 if (ret)
1499 return dev_err_probe(dev, err: ret, fmt: "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, err: -EINVAL,
1504 fmt: "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(of_node: dev->of_node);
1509 if (nr_inputs < 0)
1510 return dev_err_probe(dev, err: nr_inputs,
1511 fmt: "Invalid number of input ports\n");
1512 isl7998x->nr_inputs = nr_inputs;
1513
1514 v4l2_i2c_subdev_init(sd: &isl7998x->subdev, client, ops: &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(sd: &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(entity: &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(dev: &client->dev);
1552 v4l2_async_unregister_subdev(sd: &isl7998x->subdev);
1553 isl7998x_remove_controls(isl7998x);
1554 media_entity_cleanup(entity: &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", 0 },
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(desc: isl7998x->rstb_gpio, value: 1);
1576 gpiod_set_value(desc: isl7998x->pd_gpio, value: 0);
1577 gpiod_set_value(desc: isl7998x->rstb_gpio, value: 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(desc: isl7998x->pd_gpio, value: 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(desc: isl7998x->pd_gpio, value: 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

source code of linux/drivers/media/i2c/isl7998x.c