xref: /linux/drivers/media/i2c/imx471.c (revision f4cdf7ca9a1fdcca413157df19753f388a5a224e)
1be1589e5SKate Hsuan // SPDX-License-Identifier: GPL-2.0
2be1589e5SKate Hsuan /*
3be1589e5SKate Hsuan  * imx471.c - imx471 sensor driver
4be1589e5SKate Hsuan  *
5be1589e5SKate Hsuan  * Copyright (C) 2025 Intel Corporation
6be1589e5SKate Hsuan  * Copyright (C) 2026 Kate Hsuan <hpa@redhat.com>
7be1589e5SKate Hsuan  */
8be1589e5SKate Hsuan 
9be1589e5SKate Hsuan #include <linux/clk.h>
10be1589e5SKate Hsuan #include <linux/delay.h>
11be1589e5SKate Hsuan #include <linux/i2c.h>
12be1589e5SKate Hsuan #include <linux/module.h>
13be1589e5SKate Hsuan #include <linux/pm_runtime.h>
14be1589e5SKate Hsuan #include <linux/regulator/consumer.h>
15be1589e5SKate Hsuan #include <media/v4l2-cci.h>
16be1589e5SKate Hsuan #include <media/v4l2-ctrls.h>
17be1589e5SKate Hsuan #include <media/v4l2-subdev.h>
18be1589e5SKate Hsuan #include <media/v4l2-fwnode.h>
19be1589e5SKate Hsuan 
20be1589e5SKate Hsuan #define IMX471_REG_MODE_SELECT			CCI_REG8(0x0100)
21be1589e5SKate Hsuan #define IMX471_MODE_STANDBY			0x00
22be1589e5SKate Hsuan #define IMX471_MODE_STREAMING			0x01
23be1589e5SKate Hsuan 
24be1589e5SKate Hsuan /* Chip ID */
25be1589e5SKate Hsuan #define IMX471_REG_CHIP_ID			CCI_REG16(0x0016)
26be1589e5SKate Hsuan #define IMX471_CHIP_ID				0x0471
27be1589e5SKate Hsuan 
28be1589e5SKate Hsuan /* V_TIMING internal */
29be1589e5SKate Hsuan #define IMX471_REG_FLL				CCI_REG16(0x0340)
30be1589e5SKate Hsuan #define IMX471_FLL_MAX				0xffff
31be1589e5SKate Hsuan 
32be1589e5SKate Hsuan /* Exposure control */
33be1589e5SKate Hsuan #define IMX471_REG_EXPOSURE			CCI_REG16(0x0202)
34be1589e5SKate Hsuan #define IMX471_EXPOSURE_MIN			1
35be1589e5SKate Hsuan #define IMX471_EXPOSURE_STEP			1
36be1589e5SKate Hsuan #define IMX471_EXPOSURE_DEFAULT			1270
37be1589e5SKate Hsuan 
38be1589e5SKate Hsuan /* Default exposure margin */
39be1589e5SKate Hsuan #define IMX471_EXPOSURE_MARGIN			18
40be1589e5SKate Hsuan 
41be1589e5SKate Hsuan /* Analog gain control */
42be1589e5SKate Hsuan #define IMX471_REG_ANALOG_GAIN			CCI_REG16(0x0204)
43be1589e5SKate Hsuan #define IMX471_ANA_GAIN_MIN			0
44be1589e5SKate Hsuan #define IMX471_ANA_GAIN_MAX			800
45be1589e5SKate Hsuan #define IMX471_ANA_GAIN_STEP			1
46be1589e5SKate Hsuan #define IMX471_ANA_GAIN_DEFAULT			0
47be1589e5SKate Hsuan 
48be1589e5SKate Hsuan /* Digital gain control */
49be1589e5SKate Hsuan #define IMX471_REG_DPGA_USE_GLOBAL_GAIN		CCI_REG16(0x3ff9)
50be1589e5SKate Hsuan #define IMX471_REG_DIG_GAIN_GLOBAL		CCI_REG16(0x020e)
51be1589e5SKate Hsuan #define IMX471_DGTL_GAIN_MIN			256
52be1589e5SKate Hsuan #define IMX471_DGTL_GAIN_MAX			4095
53be1589e5SKate Hsuan #define IMX471_DGTL_GAIN_STEP			1
54be1589e5SKate Hsuan #define IMX471_DGTL_GAIN_DEFAULT		256
55be1589e5SKate Hsuan 
56be1589e5SKate Hsuan /* HFLIP and VFLIP control */
57be1589e5SKate Hsuan #define IMX471_REG_ORIENTATION			CCI_REG8(0x0101)
58be1589e5SKate Hsuan 
59be1589e5SKate Hsuan /* Test Pattern Control */
60be1589e5SKate Hsuan #define IMX471_REG_TEST_PATTERN			CCI_REG8(0x0600)
61be1589e5SKate Hsuan 
62be1589e5SKate Hsuan /* default link frequency and external clock */
63be1589e5SKate Hsuan #define IMX471_LINK_FREQ_DEFAULT		200000000LL
64be1589e5SKate Hsuan #define IMX471_EXT_CLK				19200000
65be1589e5SKate Hsuan 
66be1589e5SKate Hsuan /* PLL */
67be1589e5SKate Hsuan #define IMX471_REG_VTPXCK_DIV			CCI_REG8(0x0301)
68be1589e5SKate Hsuan #define IMX471_REG_VTSYCK_DIV			CCI_REG8(0x0303)
69be1589e5SKate Hsuan #define IMX471_REG_PREPLLCK_VT_DIV		CCI_REG8(0x0305)
70be1589e5SKate Hsuan #define IMX471_REG_PLL_VT_MPY			CCI_REG16(0x0306)
71be1589e5SKate Hsuan #define IMX471_REG_OPPXCK_DIV			CCI_REG8(0x0309)
72be1589e5SKate Hsuan #define IMX471_REG_OPSYCK_DIV			CCI_REG8(0x030b)
73be1589e5SKate Hsuan #define IMX471_REG_PLL_MULT_DRIV		CCI_REG8(0x0310)
74be1589e5SKate Hsuan #define IMX471_PLL_SINGLE			0
75be1589e5SKate Hsuan #define IMX471_PLL_DUAL				1
76be1589e5SKate Hsuan 
77be1589e5SKate Hsuan /* IMX471 native and active pixel array size */
78be1589e5SKate Hsuan #define IMX471_NATIVE_WIDTH			4672
79be1589e5SKate Hsuan #define IMX471_NATIVE_HEIGHT			3512
80be1589e5SKate Hsuan #define IMX471_PIXEL_ARRAY_LEFT			8
81be1589e5SKate Hsuan #define IMX471_PIXEL_ARRAY_TOP			8
82be1589e5SKate Hsuan #define IMX471_PIXEL_ARRAY_WIDTH		4656
83be1589e5SKate Hsuan #define IMX471_PIXEL_ARRAY_HEIGHT		3496
84be1589e5SKate Hsuan 
85be1589e5SKate Hsuan #define IMX471_REG_EXCK_FREQ			CCI_REG16(0x0136)
86be1589e5SKate Hsuan 
87be1589e5SKate Hsuan #define IMX471_REG_CSI_DATA_FORMAT		CCI_REG16(0x0112)
88be1589e5SKate Hsuan #define IMX471_CSI_DATA_FORMAT_RAW10		0x0a0a
89be1589e5SKate Hsuan 
90be1589e5SKate Hsuan #define IMX471_REG_CSI_LANE_MODE		CCI_REG8(0x0114)
91be1589e5SKate Hsuan #define IMX471_CSI_2_LANE_MODE			1
92be1589e5SKate Hsuan #define IMX471_CSI_4_LANE_MODE			3
93be1589e5SKate Hsuan 
94be1589e5SKate Hsuan #define IMX471_REG_X_ADD_STA			CCI_REG16(0x0344)
95be1589e5SKate Hsuan #define IMX471_REG_Y_ADD_STA			CCI_REG16(0x0346)
96be1589e5SKate Hsuan #define IMX471_REG_X_ADD_END			CCI_REG16(0x0348)
97be1589e5SKate Hsuan #define IMX471_REG_Y_ADD_END			CCI_REG16(0x034a)
98be1589e5SKate Hsuan #define IMX471_REG_X_OUTPUT_SIZE		CCI_REG16(0x034c)
99be1589e5SKate Hsuan #define IMX471_REG_Y_OUTPUT_SIZE		CCI_REG16(0x034e)
100be1589e5SKate Hsuan #define IMX471_REG_X_EVEN_INC			CCI_REG8(0x0381)
101be1589e5SKate Hsuan #define IMX471_REG_X_ODD_INC			CCI_REG8(0x0383)
102be1589e5SKate Hsuan #define IMX471_REG_Y_EVEN_INC			CCI_REG8(0x0385)
103be1589e5SKate Hsuan #define IMX471_REG_Y_ODD_INC			CCI_REG8(0x0387)
104be1589e5SKate Hsuan 
105be1589e5SKate Hsuan #define IMX471_REG_DIG_CROP_X_OFFSET		CCI_REG16(0x0408)
106be1589e5SKate Hsuan #define IMX471_REG_DIG_CROP_Y_OFFSET		CCI_REG16(0x040a)
107be1589e5SKate Hsuan #define IMX471_REG_DIG_CROP_WIDTH		CCI_REG16(0x040c)
108be1589e5SKate Hsuan #define IMX471_REG_DIG_CROP_HEIGHT		CCI_REG16(0x040e)
109be1589e5SKate Hsuan 
110be1589e5SKate Hsuan /* Binning mode */
111be1589e5SKate Hsuan #define IMX471_REG_BINNING_MODE			CCI_REG8(0x0900)
112be1589e5SKate Hsuan #define IMX471_BINNING_NONE			0
113be1589e5SKate Hsuan #define IMX471_BINNING_ENABLE			1
114be1589e5SKate Hsuan #define IMX471_REG_BINNING_TYPE			CCI_REG8(0x0901)
115be1589e5SKate Hsuan #define IMX471_REG_BINNING_WEIGHTING		CCI_REG8(0x0902)
116be1589e5SKate Hsuan 
117be1589e5SKate Hsuan #define to_imx471(_sd) container_of_const(_sd, struct imx471, sd)
118be1589e5SKate Hsuan 
119be1589e5SKate Hsuan static const char * const imx471_supply_name[] = {
120be1589e5SKate Hsuan 	"vana",
121be1589e5SKate Hsuan };
122be1589e5SKate Hsuan 
123be1589e5SKate Hsuan struct imx471_mode {
124be1589e5SKate Hsuan 	u32 width;
125be1589e5SKate Hsuan 	u32 height;
126be1589e5SKate Hsuan 
127be1589e5SKate Hsuan 	/* V-timing */
128be1589e5SKate Hsuan 	u32 fll_def;
129be1589e5SKate Hsuan 	u32 fll_min;
130be1589e5SKate Hsuan 
131be1589e5SKate Hsuan 	/* H-timing */
132be1589e5SKate Hsuan 	u32 llp;
133be1589e5SKate Hsuan 
134be1589e5SKate Hsuan 	const struct cci_reg_sequence *default_mode_regs;
135be1589e5SKate Hsuan 	unsigned int default_mode_regs_length;
136be1589e5SKate Hsuan };
137be1589e5SKate Hsuan 
138be1589e5SKate Hsuan struct imx471 {
139be1589e5SKate Hsuan 	struct v4l2_subdev sd;
140be1589e5SKate Hsuan 	struct media_pad pad;
141be1589e5SKate Hsuan 
142be1589e5SKate Hsuan 	struct v4l2_ctrl_handler ctrl_handler;
143be1589e5SKate Hsuan 	struct v4l2_ctrl *vblank;
144be1589e5SKate Hsuan 	struct v4l2_ctrl *hblank;
145be1589e5SKate Hsuan 	struct v4l2_ctrl *vflip;
146be1589e5SKate Hsuan 	struct v4l2_ctrl *hflip;
147be1589e5SKate Hsuan 	struct v4l2_ctrl *exposure;
148be1589e5SKate Hsuan 
149be1589e5SKate Hsuan 	struct gpio_desc *reset_gpio;
150be1589e5SKate Hsuan 	struct regulator_bulk_data supplies[ARRAY_SIZE(imx471_supply_name)];
151be1589e5SKate Hsuan 	struct clk *img_clk;
152be1589e5SKate Hsuan 
153be1589e5SKate Hsuan 	struct device *dev;
154be1589e5SKate Hsuan 	struct regmap *regmap;
155be1589e5SKate Hsuan };
156be1589e5SKate Hsuan 
157be1589e5SKate Hsuan static const struct cci_reg_sequence imx471_global_regs[] = {
158be1589e5SKate Hsuan 	{ IMX471_REG_EXCK_FREQ, 0x1333 },
159be1589e5SKate Hsuan 	{ CCI_REG8(0x3c7e), 0x08 },
160be1589e5SKate Hsuan 	{ CCI_REG8(0x3c7f), 0x05 },
161be1589e5SKate Hsuan 	{ CCI_REG8(0x3e35), 0x00 },
162be1589e5SKate Hsuan 	{ CCI_REG8(0x3e36), 0x00 },
163be1589e5SKate Hsuan 	{ CCI_REG8(0x3e37), 0x00 },
164be1589e5SKate Hsuan 	{ CCI_REG8(0x3f7f), 0x01 },
165be1589e5SKate Hsuan 	{ CCI_REG8(0x4431), 0x04 },
166be1589e5SKate Hsuan 	{ CCI_REG8(0x531c), 0x01 },
167be1589e5SKate Hsuan 	{ CCI_REG8(0x531d), 0x02 },
168be1589e5SKate Hsuan 	{ CCI_REG8(0x531e), 0x04 },
169be1589e5SKate Hsuan 	{ CCI_REG8(0x5928), 0x00 },
170be1589e5SKate Hsuan 	{ CCI_REG8(0x5929), 0x2f },
171be1589e5SKate Hsuan 	{ CCI_REG8(0x592a), 0x00 },
172be1589e5SKate Hsuan 	{ CCI_REG8(0x592b), 0x85 },
173be1589e5SKate Hsuan 	{ CCI_REG8(0x592c), 0x00 },
174be1589e5SKate Hsuan 	{ CCI_REG8(0x592d), 0x32 },
175be1589e5SKate Hsuan 	{ CCI_REG8(0x592e), 0x00 },
176be1589e5SKate Hsuan 	{ CCI_REG8(0x592f), 0x88 },
177be1589e5SKate Hsuan 	{ CCI_REG8(0x5930), 0x00 },
178be1589e5SKate Hsuan 	{ CCI_REG8(0x5931), 0x3d },
179be1589e5SKate Hsuan 	{ CCI_REG8(0x5932), 0x00 },
180be1589e5SKate Hsuan 	{ CCI_REG8(0x5933), 0x93 },
181be1589e5SKate Hsuan 	{ CCI_REG8(0x5938), 0x00 },
182be1589e5SKate Hsuan 	{ CCI_REG8(0x5939), 0x24 },
183be1589e5SKate Hsuan 	{ CCI_REG8(0x593a), 0x00 },
184be1589e5SKate Hsuan 	{ CCI_REG8(0x593b), 0x7a },
185be1589e5SKate Hsuan 	{ CCI_REG8(0x593c), 0x00 },
186be1589e5SKate Hsuan 	{ CCI_REG8(0x593d), 0x24 },
187be1589e5SKate Hsuan 	{ CCI_REG8(0x593e), 0x00 },
188be1589e5SKate Hsuan 	{ CCI_REG8(0x593f), 0x7a },
189be1589e5SKate Hsuan 	{ CCI_REG8(0x5940), 0x00 },
190be1589e5SKate Hsuan 	{ CCI_REG8(0x5941), 0x2f },
191be1589e5SKate Hsuan 	{ CCI_REG8(0x5942), 0x00 },
192be1589e5SKate Hsuan 	{ CCI_REG8(0x5943), 0x85 },
193be1589e5SKate Hsuan 	{ CCI_REG8(0x5f0e), 0x6e },
194be1589e5SKate Hsuan 	{ CCI_REG8(0x5f11), 0xc6 },
195be1589e5SKate Hsuan 	{ CCI_REG8(0x5f17), 0x5e },
196be1589e5SKate Hsuan 	{ CCI_REG8(0x7990), 0x01 },
197be1589e5SKate Hsuan 	{ CCI_REG8(0x7993), 0x5d },
198be1589e5SKate Hsuan 	{ CCI_REG8(0x7994), 0x5d },
199be1589e5SKate Hsuan 	{ CCI_REG8(0x7995), 0xa1 },
200be1589e5SKate Hsuan 	{ CCI_REG8(0x799a), 0x01 },
201be1589e5SKate Hsuan 	{ CCI_REG8(0x799d), 0x00 },
202be1589e5SKate Hsuan 	{ CCI_REG8(0x8169), 0x01 },
203be1589e5SKate Hsuan 	{ CCI_REG8(0x8359), 0x01 },
204be1589e5SKate Hsuan 	{ CCI_REG8(0x9302), 0x1e },
205be1589e5SKate Hsuan 	{ CCI_REG8(0x9306), 0x1f },
206be1589e5SKate Hsuan 	{ CCI_REG8(0x930a), 0x26 },
207be1589e5SKate Hsuan 	{ CCI_REG8(0x930e), 0x23 },
208be1589e5SKate Hsuan 	{ CCI_REG8(0x9312), 0x23 },
209be1589e5SKate Hsuan 	{ CCI_REG8(0x9316), 0x2c },
210be1589e5SKate Hsuan 	{ CCI_REG8(0x9317), 0x19 },
211be1589e5SKate Hsuan 	{ CCI_REG8(0xb046), 0x01 },
212be1589e5SKate Hsuan 	{ CCI_REG8(0xb048), 0x01 },
213be1589e5SKate Hsuan };
214be1589e5SKate Hsuan 
215be1589e5SKate Hsuan static const struct cci_reg_sequence mode_1928x1088_regs[] = {
216be1589e5SKate Hsuan 	{ IMX471_REG_CSI_DATA_FORMAT, IMX471_CSI_DATA_FORMAT_RAW10 },
217be1589e5SKate Hsuan 	{ IMX471_REG_CSI_LANE_MODE, IMX471_CSI_4_LANE_MODE },
218be1589e5SKate Hsuan 	{ IMX471_REG_X_ADD_STA, 8 },
219be1589e5SKate Hsuan 	{ IMX471_REG_Y_ADD_STA, 408 },
220be1589e5SKate Hsuan 	{ IMX471_REG_X_ADD_END, 4647 },
221be1589e5SKate Hsuan 	{ IMX471_REG_Y_ADD_END, 3051 },
222be1589e5SKate Hsuan 	{ IMX471_REG_X_EVEN_INC, 1 },
223be1589e5SKate Hsuan 	{ IMX471_REG_X_ODD_INC, 1 },
224be1589e5SKate Hsuan 	{ IMX471_REG_Y_EVEN_INC, 1 },
225be1589e5SKate Hsuan 	{ IMX471_REG_Y_ODD_INC, 1 },
226be1589e5SKate Hsuan 	{ IMX471_REG_BINNING_MODE, IMX471_BINNING_ENABLE },
227be1589e5SKate Hsuan 	{ IMX471_REG_BINNING_TYPE, 0x22 },
228be1589e5SKate Hsuan 	{ IMX471_REG_BINNING_WEIGHTING, 0x08 },
229be1589e5SKate Hsuan 	{ IMX471_REG_DIG_CROP_X_OFFSET, 208 },
230be1589e5SKate Hsuan 	{ IMX471_REG_DIG_CROP_Y_OFFSET, 108 },
231be1589e5SKate Hsuan 	{ IMX471_REG_DIG_CROP_WIDTH, 1928 },
232be1589e5SKate Hsuan 	{ IMX471_REG_DIG_CROP_HEIGHT, 1088 },
233be1589e5SKate Hsuan 	{ IMX471_REG_X_OUTPUT_SIZE, 1928 },
234be1589e5SKate Hsuan 	{ IMX471_REG_Y_OUTPUT_SIZE, 1088 },
235be1589e5SKate Hsuan 	{ IMX471_REG_VTPXCK_DIV, 0x06 },
236be1589e5SKate Hsuan 	{ IMX471_REG_VTSYCK_DIV, 0x02 },
237be1589e5SKate Hsuan 	{ IMX471_REG_PREPLLCK_VT_DIV, 0x02 },
238be1589e5SKate Hsuan 	{ IMX471_REG_PLL_VT_MPY, 0x0079 },
239be1589e5SKate Hsuan 	{ IMX471_REG_OPSYCK_DIV, 0x01 },
240be1589e5SKate Hsuan 	{ CCI_REG8(0x030d), 0x02 },
241be1589e5SKate Hsuan 	{ CCI_REG8(0x030e), 0x00 },
242be1589e5SKate Hsuan 	{ CCI_REG8(0x030f), 0x53 },
243be1589e5SKate Hsuan 	{ IMX471_REG_PLL_MULT_DRIV, IMX471_PLL_DUAL },
244be1589e5SKate Hsuan 	{ CCI_REG8(0x3f4c), 0x81 },
245be1589e5SKate Hsuan 	{ CCI_REG8(0x3f4d), 0x81 },
246be1589e5SKate Hsuan 	{ CCI_REG8(0x3f78), 0x01 },
247be1589e5SKate Hsuan 	{ CCI_REG8(0x3f79), 0x31 },
248be1589e5SKate Hsuan 	{ CCI_REG8(0x3ffe), 0x00 },
249be1589e5SKate Hsuan 	{ CCI_REG8(0x3fff), 0x8a },
250be1589e5SKate Hsuan 	{ CCI_REG8(0x5f0a), 0xb6 },
251be1589e5SKate Hsuan };
252be1589e5SKate Hsuan 
253be1589e5SKate Hsuan static const char * const imx471_test_pattern_menu[] = {
254be1589e5SKate Hsuan 	"Disabled",
255be1589e5SKate Hsuan 	"Solid Colour",
256be1589e5SKate Hsuan 	"Eight Vertical Colour Bars",
257be1589e5SKate Hsuan 	"Colour Bars With Fade to Grey",
258be1589e5SKate Hsuan 	"Pseudorandom Sequence (PN9)",
259be1589e5SKate Hsuan };
260be1589e5SKate Hsuan 
261be1589e5SKate Hsuan static const s64 link_freq_menu_items[] = {
262be1589e5SKate Hsuan 	IMX471_LINK_FREQ_DEFAULT,
263be1589e5SKate Hsuan };
264be1589e5SKate Hsuan 
265be1589e5SKate Hsuan /*
266be1589e5SKate Hsuan  * The Bayer formats for the flipping.
267be1589e5SKate Hsuan  * - no flip
268be1589e5SKate Hsuan  * - h flip
269be1589e5SKate Hsuan  * - v flip
270be1589e5SKate Hsuan  * - h and v flips
271be1589e5SKate Hsuan  */
272be1589e5SKate Hsuan static const u32 imx471_hv_flips_bayer_order[] = {
273be1589e5SKate Hsuan 	MEDIA_BUS_FMT_SRGGB10_1X10,
274be1589e5SKate Hsuan 	MEDIA_BUS_FMT_SGRBG10_1X10,
275be1589e5SKate Hsuan 	MEDIA_BUS_FMT_SGBRG10_1X10,
276be1589e5SKate Hsuan 	MEDIA_BUS_FMT_SBGGR10_1X10,
277be1589e5SKate Hsuan };
278be1589e5SKate Hsuan 
279be1589e5SKate Hsuan static const struct imx471_mode imx471_modes[] = {
280be1589e5SKate Hsuan 	{
281be1589e5SKate Hsuan 		.width = 1928,
282be1589e5SKate Hsuan 		.height = 1088,
283be1589e5SKate Hsuan 		.fll_def = 1308,
284be1589e5SKate Hsuan 		.fll_min = 1308,
285be1589e5SKate Hsuan 		.llp = 2328,
286be1589e5SKate Hsuan 		.default_mode_regs = mode_1928x1088_regs,
287be1589e5SKate Hsuan 		.default_mode_regs_length = ARRAY_SIZE(mode_1928x1088_regs),
288be1589e5SKate Hsuan 	},
289be1589e5SKate Hsuan };
290be1589e5SKate Hsuan 
291be1589e5SKate Hsuan static int imx471_get_regulators(struct device *dev, struct imx471 *sensor)
292be1589e5SKate Hsuan {
293be1589e5SKate Hsuan 	for (unsigned int i = 0; i < ARRAY_SIZE(imx471_supply_name); i++)
294be1589e5SKate Hsuan 		sensor->supplies[i].supply = imx471_supply_name[i];
295be1589e5SKate Hsuan 
296be1589e5SKate Hsuan 	return devm_regulator_bulk_get(dev, ARRAY_SIZE(imx471_supply_name),
297be1589e5SKate Hsuan 				       sensor->supplies);
298be1589e5SKate Hsuan }
299be1589e5SKate Hsuan 
300be1589e5SKate Hsuan static int imx471_set_ctrl(struct v4l2_ctrl *ctrl)
301be1589e5SKate Hsuan {
302be1589e5SKate Hsuan 	struct imx471 *sensor = container_of_const(ctrl->handler,
303be1589e5SKate Hsuan 						   struct imx471,
304be1589e5SKate Hsuan 						   ctrl_handler);
305be1589e5SKate Hsuan 	struct v4l2_subdev_state *state =
306be1589e5SKate Hsuan 			v4l2_subdev_get_locked_active_state(&sensor->sd);
307be1589e5SKate Hsuan 	const struct v4l2_mbus_framefmt *format =
308be1589e5SKate Hsuan 			v4l2_subdev_state_get_format(state, 0);
309be1589e5SKate Hsuan 	int ret;
310be1589e5SKate Hsuan 
311be1589e5SKate Hsuan 	if (ctrl->id == V4L2_CID_VBLANK) {
312be1589e5SKate Hsuan 		s64 exposure_max = format->height + ctrl->val -
313be1589e5SKate Hsuan 				   IMX471_EXPOSURE_MARGIN;
314be1589e5SKate Hsuan 		ret = __v4l2_ctrl_modify_range(sensor->exposure,
315be1589e5SKate Hsuan 					       sensor->exposure->minimum,
316be1589e5SKate Hsuan 					       exposure_max,
317be1589e5SKate Hsuan 					       sensor->exposure->step,
318be1589e5SKate Hsuan 					       exposure_max);
319be1589e5SKate Hsuan 		if (ret)
320be1589e5SKate Hsuan 			return ret;
321be1589e5SKate Hsuan 	}
322be1589e5SKate Hsuan 
323be1589e5SKate Hsuan 	if (!pm_runtime_get_if_in_use(sensor->dev))
324be1589e5SKate Hsuan 		return 0;
325be1589e5SKate Hsuan 
326be1589e5SKate Hsuan 	switch (ctrl->id) {
327be1589e5SKate Hsuan 	case V4L2_CID_ANALOGUE_GAIN:
328be1589e5SKate Hsuan 		ret = cci_write(sensor->regmap, IMX471_REG_ANALOG_GAIN,
329be1589e5SKate Hsuan 				ctrl->val, NULL);
330be1589e5SKate Hsuan 		break;
331be1589e5SKate Hsuan 	case V4L2_CID_DIGITAL_GAIN:
332be1589e5SKate Hsuan 		ret = cci_write(sensor->regmap, IMX471_REG_DIG_GAIN_GLOBAL,
333be1589e5SKate Hsuan 				ctrl->val, NULL);
334be1589e5SKate Hsuan 		break;
335be1589e5SKate Hsuan 	case V4L2_CID_EXPOSURE:
336be1589e5SKate Hsuan 		ret = cci_write(sensor->regmap, IMX471_REG_EXPOSURE,
337*b272a178SDavid Carlier 				ctrl->val, NULL);
338be1589e5SKate Hsuan 		break;
339be1589e5SKate Hsuan 	case V4L2_CID_VBLANK:
340be1589e5SKate Hsuan 		/* Update FLL that meets expected vertical blanking */
341be1589e5SKate Hsuan 		ret = cci_write(sensor->regmap, IMX471_REG_FLL,
342*b272a178SDavid Carlier 				format->height + ctrl->val, NULL);
343be1589e5SKate Hsuan 		break;
344be1589e5SKate Hsuan 	case V4L2_CID_TEST_PATTERN:
345be1589e5SKate Hsuan 		ret = cci_write(sensor->regmap, IMX471_REG_TEST_PATTERN,
346be1589e5SKate Hsuan 				ctrl->val, NULL);
347be1589e5SKate Hsuan 		break;
348be1589e5SKate Hsuan 	case V4L2_CID_HFLIP:
349be1589e5SKate Hsuan 	case V4L2_CID_VFLIP:
350be1589e5SKate Hsuan 		ret = cci_write(sensor->regmap, IMX471_REG_ORIENTATION,
351be1589e5SKate Hsuan 				sensor->hflip->val | sensor->vflip->val << 1,
352be1589e5SKate Hsuan 				NULL);
353be1589e5SKate Hsuan 		break;
354be1589e5SKate Hsuan 	default:
355be1589e5SKate Hsuan 		ret = -EINVAL;
356be1589e5SKate Hsuan 		dev_err(sensor->dev, "ctrl(id:0x%x,val:0x%x) is not handled\n",
357be1589e5SKate Hsuan 			ctrl->id, ctrl->val);
358be1589e5SKate Hsuan 		break;
359be1589e5SKate Hsuan 	}
360be1589e5SKate Hsuan 
361be1589e5SKate Hsuan 	pm_runtime_put(sensor->dev);
362be1589e5SKate Hsuan 
363be1589e5SKate Hsuan 	return ret;
364be1589e5SKate Hsuan }
365be1589e5SKate Hsuan 
366be1589e5SKate Hsuan static const struct v4l2_ctrl_ops imx471_ctrl_ops = {
367be1589e5SKate Hsuan 	.s_ctrl = imx471_set_ctrl,
368be1589e5SKate Hsuan };
369be1589e5SKate Hsuan 
370be1589e5SKate Hsuan static u32 imx471_get_format_code(struct imx471 *sensor)
371be1589e5SKate Hsuan {
372be1589e5SKate Hsuan 	unsigned int i;
373be1589e5SKate Hsuan 
374be1589e5SKate Hsuan 	i = (sensor->vflip->val ? 2 : 0) | (sensor->hflip->val ? 1 : 0);
375be1589e5SKate Hsuan 
376be1589e5SKate Hsuan 	return imx471_hv_flips_bayer_order[i];
377be1589e5SKate Hsuan }
378be1589e5SKate Hsuan 
379be1589e5SKate Hsuan static int imx471_enum_mbus_code(struct v4l2_subdev *sd,
380be1589e5SKate Hsuan 				 struct v4l2_subdev_state *sd_state,
381be1589e5SKate Hsuan 				 struct v4l2_subdev_mbus_code_enum *code)
382be1589e5SKate Hsuan {
383be1589e5SKate Hsuan 	struct imx471 *sensor = to_imx471(sd);
384be1589e5SKate Hsuan 
385be1589e5SKate Hsuan 	if (code->index >= (ARRAY_SIZE(imx471_hv_flips_bayer_order) / 4))
386be1589e5SKate Hsuan 		return -EINVAL;
387be1589e5SKate Hsuan 
388be1589e5SKate Hsuan 	code->code = imx471_get_format_code(sensor);
389be1589e5SKate Hsuan 
390be1589e5SKate Hsuan 	return 0;
391be1589e5SKate Hsuan }
392be1589e5SKate Hsuan 
393be1589e5SKate Hsuan static int imx471_enum_frame_size(struct v4l2_subdev *sd,
394be1589e5SKate Hsuan 				  struct v4l2_subdev_state *sd_state,
395be1589e5SKate Hsuan 				  struct v4l2_subdev_frame_size_enum *fse)
396be1589e5SKate Hsuan {
397be1589e5SKate Hsuan 	if (fse->index >= ARRAY_SIZE(imx471_modes))
398be1589e5SKate Hsuan 		return -EINVAL;
399be1589e5SKate Hsuan 
400be1589e5SKate Hsuan 	fse->min_width = imx471_modes[fse->index].width;
401be1589e5SKate Hsuan 	fse->max_width = fse->min_width;
402be1589e5SKate Hsuan 	fse->min_height = imx471_modes[fse->index].height;
403be1589e5SKate Hsuan 	fse->max_height = fse->min_height;
404be1589e5SKate Hsuan 
405be1589e5SKate Hsuan 	return 0;
406be1589e5SKate Hsuan }
407be1589e5SKate Hsuan 
408be1589e5SKate Hsuan static void imx471_update_pad_format(struct imx471 *sensor,
409be1589e5SKate Hsuan 				     const struct imx471_mode *mode,
410be1589e5SKate Hsuan 				     struct v4l2_subdev_format *fmt)
411be1589e5SKate Hsuan {
412be1589e5SKate Hsuan 	fmt->format.code = imx471_get_format_code(sensor);
413be1589e5SKate Hsuan 	fmt->format.width = mode->width;
414be1589e5SKate Hsuan 	fmt->format.height = mode->height;
415be1589e5SKate Hsuan 	fmt->format.field = V4L2_FIELD_NONE;
416be1589e5SKate Hsuan }
417be1589e5SKate Hsuan 
418be1589e5SKate Hsuan static int imx471_set_pad_format(struct v4l2_subdev *sd,
419be1589e5SKate Hsuan 				 struct v4l2_subdev_state *sd_state,
420be1589e5SKate Hsuan 				 struct v4l2_subdev_format *fmt)
421be1589e5SKate Hsuan {
422be1589e5SKate Hsuan 	struct imx471 *sensor = to_imx471(sd);
423be1589e5SKate Hsuan 	const struct imx471_mode *mode;
424be1589e5SKate Hsuan 	int h_blank, ret;
425be1589e5SKate Hsuan 
426be1589e5SKate Hsuan 	mode = v4l2_find_nearest_size(imx471_modes, ARRAY_SIZE(imx471_modes),
427be1589e5SKate Hsuan 				      width, height, fmt->format.width,
428be1589e5SKate Hsuan 				      fmt->format.height);
429be1589e5SKate Hsuan 
430be1589e5SKate Hsuan 	imx471_update_pad_format(sensor, mode, fmt);
431be1589e5SKate Hsuan 
432be1589e5SKate Hsuan 	*v4l2_subdev_state_get_format(sd_state, fmt->pad) = fmt->format;
433be1589e5SKate Hsuan 
434be1589e5SKate Hsuan 	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
435be1589e5SKate Hsuan 		return 0;
436be1589e5SKate Hsuan 
437be1589e5SKate Hsuan 	if (media_entity_is_streaming(&sensor->sd.entity))
438be1589e5SKate Hsuan 		return -EBUSY;
439be1589e5SKate Hsuan 
440be1589e5SKate Hsuan 	ret = __v4l2_ctrl_modify_range(sensor->vblank,
441be1589e5SKate Hsuan 				       mode->fll_min - mode->height,
442be1589e5SKate Hsuan 				       IMX471_FLL_MAX - mode->height,
443be1589e5SKate Hsuan 				       1,
444be1589e5SKate Hsuan 				       mode->fll_def - mode->height);
445be1589e5SKate Hsuan 	if (ret)
446be1589e5SKate Hsuan 		return ret;
447be1589e5SKate Hsuan 
448be1589e5SKate Hsuan 	h_blank = mode->llp - mode->width;
449be1589e5SKate Hsuan 	/*
450be1589e5SKate Hsuan 	 * Currently hblank is not changeable.
451be1589e5SKate Hsuan 	 * So FPS control is done only by vblank.
452be1589e5SKate Hsuan 	 */
453be1589e5SKate Hsuan 	return __v4l2_ctrl_modify_range(sensor->hblank, h_blank,
454be1589e5SKate Hsuan 					h_blank, 1, h_blank);
455be1589e5SKate Hsuan }
456be1589e5SKate Hsuan 
457be1589e5SKate Hsuan static int imx471_get_selection(struct v4l2_subdev *sd,
458be1589e5SKate Hsuan 				struct v4l2_subdev_state *sd_state,
459be1589e5SKate Hsuan 				struct v4l2_subdev_selection *sel)
460be1589e5SKate Hsuan {
461be1589e5SKate Hsuan 	switch (sel->target) {
462be1589e5SKate Hsuan 	case V4L2_SEL_TGT_CROP:
463be1589e5SKate Hsuan 		sel->r = *v4l2_subdev_state_get_crop(sd_state, sel->pad);
464be1589e5SKate Hsuan 		break;
465be1589e5SKate Hsuan 
466be1589e5SKate Hsuan 	case V4L2_SEL_TGT_NATIVE_SIZE:
467be1589e5SKate Hsuan 		sel->r.top = 0;
468be1589e5SKate Hsuan 		sel->r.left = 0;
469be1589e5SKate Hsuan 		sel->r.width = IMX471_NATIVE_WIDTH;
470be1589e5SKate Hsuan 		sel->r.height = IMX471_NATIVE_HEIGHT;
471be1589e5SKate Hsuan 		return 0;
472be1589e5SKate Hsuan 
473be1589e5SKate Hsuan 	case V4L2_SEL_TGT_CROP_DEFAULT:
474be1589e5SKate Hsuan 	case V4L2_SEL_TGT_CROP_BOUNDS:
475be1589e5SKate Hsuan 		sel->r.top = IMX471_PIXEL_ARRAY_TOP;
476be1589e5SKate Hsuan 		sel->r.left = IMX471_PIXEL_ARRAY_LEFT;
477be1589e5SKate Hsuan 		sel->r.width = IMX471_PIXEL_ARRAY_WIDTH;
478be1589e5SKate Hsuan 		sel->r.height = IMX471_PIXEL_ARRAY_HEIGHT;
479be1589e5SKate Hsuan 		return 0;
480be1589e5SKate Hsuan 	}
481be1589e5SKate Hsuan 
482be1589e5SKate Hsuan 	return -EINVAL;
483be1589e5SKate Hsuan }
484be1589e5SKate Hsuan 
485be1589e5SKate Hsuan static int imx471_init_state(struct v4l2_subdev *sd,
486be1589e5SKate Hsuan 			     struct v4l2_subdev_state *sd_state)
487be1589e5SKate Hsuan {
488be1589e5SKate Hsuan 	struct v4l2_subdev_format fmt = {
489be1589e5SKate Hsuan 		.which = V4L2_SUBDEV_FORMAT_TRY,
490be1589e5SKate Hsuan 		.format = {
491be1589e5SKate Hsuan 			.code = MEDIA_BUS_FMT_SRGGB10_1X10,
492be1589e5SKate Hsuan 			.width = imx471_modes[0].width,
493be1589e5SKate Hsuan 			.height = imx471_modes[0].height,
494be1589e5SKate Hsuan 		},
495be1589e5SKate Hsuan 	};
496be1589e5SKate Hsuan 
497be1589e5SKate Hsuan 	return imx471_set_pad_format(sd, sd_state, &fmt);
498be1589e5SKate Hsuan }
499be1589e5SKate Hsuan 
500be1589e5SKate Hsuan static int imx471_identify_module(struct imx471 *sensor)
501be1589e5SKate Hsuan {
502be1589e5SKate Hsuan 	int ret;
503be1589e5SKate Hsuan 	u64 val;
504be1589e5SKate Hsuan 
505be1589e5SKate Hsuan 	ret = cci_read(sensor->regmap, IMX471_REG_CHIP_ID, &val, NULL);
506be1589e5SKate Hsuan 	if (ret)
507be1589e5SKate Hsuan 		return dev_err_probe(sensor->dev, ret,
508be1589e5SKate Hsuan 				     "failed to read chip id\n");
509be1589e5SKate Hsuan 
510be1589e5SKate Hsuan 	if (val != IMX471_CHIP_ID)
511be1589e5SKate Hsuan 		return dev_err_probe(sensor->dev, -EIO,
512be1589e5SKate Hsuan 				     "chip id mismatch: %x!=%llx\n",
513be1589e5SKate Hsuan 				     IMX471_CHIP_ID, val);
514be1589e5SKate Hsuan 
515be1589e5SKate Hsuan 	return 0;
516be1589e5SKate Hsuan }
517be1589e5SKate Hsuan 
518be1589e5SKate Hsuan static int imx471_power_off(struct device *dev)
519be1589e5SKate Hsuan {
520be1589e5SKate Hsuan 	struct v4l2_subdev *sd = dev_get_drvdata(dev);
521be1589e5SKate Hsuan 	struct imx471 *sensor = to_imx471(sd);
522be1589e5SKate Hsuan 
523be1589e5SKate Hsuan 	clk_disable_unprepare(sensor->img_clk);
524be1589e5SKate Hsuan 	gpiod_set_value_cansleep(sensor->reset_gpio, 1);
525be1589e5SKate Hsuan 
526be1589e5SKate Hsuan 	regulator_bulk_disable(ARRAY_SIZE(imx471_supply_name),
527be1589e5SKate Hsuan 			       sensor->supplies);
528be1589e5SKate Hsuan 
529be1589e5SKate Hsuan 	return 0;
530be1589e5SKate Hsuan }
531be1589e5SKate Hsuan 
532be1589e5SKate Hsuan static int imx471_power_on(struct device *dev)
533be1589e5SKate Hsuan {
534be1589e5SKate Hsuan 	struct v4l2_subdev *sd = dev_get_drvdata(dev);
535be1589e5SKate Hsuan 	struct imx471 *sensor = to_imx471(sd);
536be1589e5SKate Hsuan 	int ret;
537be1589e5SKate Hsuan 
538be1589e5SKate Hsuan 	ret = regulator_bulk_enable(ARRAY_SIZE(imx471_supply_name),
539be1589e5SKate Hsuan 				    sensor->supplies);
540be1589e5SKate Hsuan 	if (ret < 0) {
541be1589e5SKate Hsuan 		dev_err(dev, "failed to enable regulators: %d\n", ret);
542be1589e5SKate Hsuan 		return ret;
543be1589e5SKate Hsuan 	}
544be1589e5SKate Hsuan 
545be1589e5SKate Hsuan 	ret = clk_prepare_enable(sensor->img_clk);
546be1589e5SKate Hsuan 	if (ret < 0) {
547be1589e5SKate Hsuan 		regulator_bulk_disable(ARRAY_SIZE(imx471_supply_name),
548be1589e5SKate Hsuan 				       sensor->supplies);
549be1589e5SKate Hsuan 		dev_err(dev, "failed to enable imaging clock: %d\n", ret);
550be1589e5SKate Hsuan 		return ret;
551be1589e5SKate Hsuan 	}
552be1589e5SKate Hsuan 
553be1589e5SKate Hsuan 	gpiod_set_value_cansleep(sensor->reset_gpio, 0);
554be1589e5SKate Hsuan 
555be1589e5SKate Hsuan 	usleep_range(10000, 15000);
556be1589e5SKate Hsuan 
557be1589e5SKate Hsuan 	return 0;
558be1589e5SKate Hsuan }
559be1589e5SKate Hsuan 
560be1589e5SKate Hsuan static int imx471_enable_stream(struct v4l2_subdev *sd,
561be1589e5SKate Hsuan 				struct v4l2_subdev_state *state,
562be1589e5SKate Hsuan 				u32 pad, u64 streams_mask)
563be1589e5SKate Hsuan {
564be1589e5SKate Hsuan 	struct imx471 *sensor = to_imx471(sd);
565be1589e5SKate Hsuan 	const struct imx471_mode *mode;
566be1589e5SKate Hsuan 	struct v4l2_mbus_framefmt *fmt;
567be1589e5SKate Hsuan 	int ret;
568be1589e5SKate Hsuan 
569be1589e5SKate Hsuan 	ret = pm_runtime_resume_and_get(sensor->dev);
570be1589e5SKate Hsuan 	if (ret)
571be1589e5SKate Hsuan 		return ret;
572be1589e5SKate Hsuan 
573be1589e5SKate Hsuan 	ret = imx471_identify_module(sensor);
574be1589e5SKate Hsuan 	if (ret)
575be1589e5SKate Hsuan 		goto error_powerdown;
576be1589e5SKate Hsuan 
577be1589e5SKate Hsuan 	ret = cci_multi_reg_write(sensor->regmap, imx471_global_regs,
578be1589e5SKate Hsuan 				  ARRAY_SIZE(imx471_global_regs), NULL);
579be1589e5SKate Hsuan 	if (ret) {
580be1589e5SKate Hsuan 		dev_err(sensor->dev, "failed to set global settings: %d\n",
581be1589e5SKate Hsuan 			ret);
582be1589e5SKate Hsuan 		goto error_powerdown;
583be1589e5SKate Hsuan 	}
584be1589e5SKate Hsuan 
585be1589e5SKate Hsuan 	fmt = v4l2_subdev_state_get_format(state, 0);
586be1589e5SKate Hsuan 	mode = v4l2_find_nearest_size(imx471_modes, ARRAY_SIZE(imx471_modes),
587be1589e5SKate Hsuan 				      width, height, fmt->width, fmt->height);
588be1589e5SKate Hsuan 
589be1589e5SKate Hsuan 	ret = cci_multi_reg_write(sensor->regmap, mode->default_mode_regs,
590be1589e5SKate Hsuan 				  mode->default_mode_regs_length, NULL);
591be1589e5SKate Hsuan 	if (ret) {
592be1589e5SKate Hsuan 		dev_err(sensor->dev, "failed to set mode: %d\n", ret);
593be1589e5SKate Hsuan 		goto error_powerdown;
594be1589e5SKate Hsuan 	}
595be1589e5SKate Hsuan 
596be1589e5SKate Hsuan 	ret = cci_write(sensor->regmap, IMX471_REG_DPGA_USE_GLOBAL_GAIN, 1,
597be1589e5SKate Hsuan 			NULL);
598be1589e5SKate Hsuan 	if (ret)
599be1589e5SKate Hsuan 		goto error_powerdown;
600be1589e5SKate Hsuan 
601be1589e5SKate Hsuan 	ret = __v4l2_ctrl_handler_setup(&sensor->ctrl_handler);
602be1589e5SKate Hsuan 	if (ret)
603be1589e5SKate Hsuan 		goto error_powerdown;
604be1589e5SKate Hsuan 
605be1589e5SKate Hsuan 	ret = cci_write(sensor->regmap, IMX471_REG_MODE_SELECT,
606be1589e5SKate Hsuan 			IMX471_MODE_STREAMING, NULL);
607be1589e5SKate Hsuan 	if (ret)
608be1589e5SKate Hsuan 		goto error_powerdown;
609be1589e5SKate Hsuan 
610be1589e5SKate Hsuan 	__v4l2_ctrl_grab(sensor->vflip, true);
611be1589e5SKate Hsuan 	__v4l2_ctrl_grab(sensor->hflip, true);
612be1589e5SKate Hsuan 
613be1589e5SKate Hsuan 	return ret;
614be1589e5SKate Hsuan 
615be1589e5SKate Hsuan error_powerdown:
616be1589e5SKate Hsuan 	pm_runtime_put(sensor->dev);
617be1589e5SKate Hsuan 
618be1589e5SKate Hsuan 	return ret;
619be1589e5SKate Hsuan }
620be1589e5SKate Hsuan 
621be1589e5SKate Hsuan static int imx471_disable_stream(struct v4l2_subdev *sd,
622be1589e5SKate Hsuan 				 struct v4l2_subdev_state *state,
623be1589e5SKate Hsuan 				 u32 pad, u64 streams_mask)
624be1589e5SKate Hsuan {
625be1589e5SKate Hsuan 	struct imx471 *sensor = to_imx471(sd);
626be1589e5SKate Hsuan 	int ret;
627be1589e5SKate Hsuan 
628be1589e5SKate Hsuan 	ret = cci_write(sensor->regmap, IMX471_REG_MODE_SELECT,
629be1589e5SKate Hsuan 			IMX471_MODE_STANDBY, NULL);
630be1589e5SKate Hsuan 	pm_runtime_put(sensor->dev);
631be1589e5SKate Hsuan 
632be1589e5SKate Hsuan 	if (ret)
633be1589e5SKate Hsuan 		dev_err(sensor->dev,
634be1589e5SKate Hsuan 			"failed to disable stream with return value: %d\n",
635be1589e5SKate Hsuan 			ret);
636be1589e5SKate Hsuan 
637be1589e5SKate Hsuan 	__v4l2_ctrl_grab(sensor->vflip, false);
638be1589e5SKate Hsuan 	__v4l2_ctrl_grab(sensor->hflip, false);
639be1589e5SKate Hsuan 
640be1589e5SKate Hsuan 	return 0;
641be1589e5SKate Hsuan }
642be1589e5SKate Hsuan 
643be1589e5SKate Hsuan static const struct v4l2_subdev_video_ops imx471_video_ops = {
644be1589e5SKate Hsuan 	.s_stream = v4l2_subdev_s_stream_helper,
645be1589e5SKate Hsuan };
646be1589e5SKate Hsuan 
647be1589e5SKate Hsuan static const struct v4l2_subdev_pad_ops imx471_pad_ops = {
648be1589e5SKate Hsuan 	.enum_mbus_code = imx471_enum_mbus_code,
649be1589e5SKate Hsuan 	.get_fmt = v4l2_subdev_get_fmt,
650be1589e5SKate Hsuan 	.set_fmt = imx471_set_pad_format,
651be1589e5SKate Hsuan 	.get_selection = imx471_get_selection,
652be1589e5SKate Hsuan 	.enum_frame_size = imx471_enum_frame_size,
653be1589e5SKate Hsuan 	.enable_streams = imx471_enable_stream,
654be1589e5SKate Hsuan 	.disable_streams = imx471_disable_stream,
655be1589e5SKate Hsuan };
656be1589e5SKate Hsuan 
657be1589e5SKate Hsuan static const struct v4l2_subdev_ops imx471_subdev_ops = {
658be1589e5SKate Hsuan 	.video = &imx471_video_ops,
659be1589e5SKate Hsuan 	.pad = &imx471_pad_ops,
660be1589e5SKate Hsuan };
661be1589e5SKate Hsuan 
662be1589e5SKate Hsuan static const struct v4l2_subdev_internal_ops imx471_internal_ops = {
663be1589e5SKate Hsuan 	.init_state = imx471_init_state,
664be1589e5SKate Hsuan };
665be1589e5SKate Hsuan 
666be1589e5SKate Hsuan static int imx471_init_controls(struct imx471 *sensor)
667be1589e5SKate Hsuan {
668be1589e5SKate Hsuan 	const struct imx471_mode *mode = &imx471_modes[0];
669be1589e5SKate Hsuan 	struct v4l2_fwnode_device_properties props;
670be1589e5SKate Hsuan 	struct v4l2_ctrl_handler *ctrl_hdlr;
671be1589e5SKate Hsuan 	struct v4l2_ctrl *link_freq;
672be1589e5SKate Hsuan 	s64 exposure_max, hblank;
673be1589e5SKate Hsuan 	u64 pixel_rate;
674be1589e5SKate Hsuan 	int ret;
675be1589e5SKate Hsuan 
676be1589e5SKate Hsuan 	ret = v4l2_fwnode_device_parse(sensor->dev, &props);
677be1589e5SKate Hsuan 	if (ret) {
678be1589e5SKate Hsuan 		dev_err(sensor->dev, "failed to parse fwnode: %d\n", ret);
679be1589e5SKate Hsuan 		return ret;
680be1589e5SKate Hsuan 	}
681be1589e5SKate Hsuan 
682be1589e5SKate Hsuan 	ctrl_hdlr = &sensor->ctrl_handler;
683be1589e5SKate Hsuan 	v4l2_ctrl_handler_init(ctrl_hdlr, 12);
684be1589e5SKate Hsuan 
685be1589e5SKate Hsuan 	v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx471_ctrl_ops, &props);
686be1589e5SKate Hsuan 
687be1589e5SKate Hsuan 	link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr,
688be1589e5SKate Hsuan 					   &imx471_ctrl_ops,
689be1589e5SKate Hsuan 					   V4L2_CID_LINK_FREQ,
690be1589e5SKate Hsuan 					   ARRAY_SIZE(link_freq_menu_items) - 1,
691be1589e5SKate Hsuan 					   0,
692be1589e5SKate Hsuan 					   link_freq_menu_items);
693be1589e5SKate Hsuan 
694be1589e5SKate Hsuan 	/* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample */
695be1589e5SKate Hsuan 	pixel_rate = div_u64(IMX471_LINK_FREQ_DEFAULT * 2 * 4, 10);
696be1589e5SKate Hsuan 
697be1589e5SKate Hsuan 	v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops,
698be1589e5SKate Hsuan 			  V4L2_CID_PIXEL_RATE, pixel_rate,
699be1589e5SKate Hsuan 			  pixel_rate, 1, pixel_rate);
700be1589e5SKate Hsuan 
701be1589e5SKate Hsuan 	sensor->vblank = v4l2_ctrl_new_std(ctrl_hdlr,
702be1589e5SKate Hsuan 					   &imx471_ctrl_ops,
703be1589e5SKate Hsuan 					   V4L2_CID_VBLANK,
704be1589e5SKate Hsuan 					   mode->fll_min - mode->height,
705be1589e5SKate Hsuan 					   IMX471_FLL_MAX - mode->height,
706be1589e5SKate Hsuan 					   1,
707be1589e5SKate Hsuan 					   mode->fll_def - mode->height);
708be1589e5SKate Hsuan 
709be1589e5SKate Hsuan 	hblank = mode->llp - mode->width;
710be1589e5SKate Hsuan 	sensor->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops,
711be1589e5SKate Hsuan 					   V4L2_CID_HBLANK, hblank, hblank,
712be1589e5SKate Hsuan 					   1, hblank);
713be1589e5SKate Hsuan 
714be1589e5SKate Hsuan 	/* fll >= exposure time + adjust parameter (default value is 18) */
715be1589e5SKate Hsuan 	exposure_max = mode->fll_def - IMX471_EXPOSURE_MARGIN;
716be1589e5SKate Hsuan 	sensor->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops,
717be1589e5SKate Hsuan 					     V4L2_CID_EXPOSURE,
718be1589e5SKate Hsuan 					     IMX471_EXPOSURE_MIN, exposure_max,
719be1589e5SKate Hsuan 					     IMX471_EXPOSURE_STEP,
720be1589e5SKate Hsuan 					     IMX471_EXPOSURE_DEFAULT);
721be1589e5SKate Hsuan 
722be1589e5SKate Hsuan 	v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
723be1589e5SKate Hsuan 			  IMX471_ANA_GAIN_MIN, IMX471_ANA_GAIN_MAX,
724be1589e5SKate Hsuan 			  IMX471_ANA_GAIN_STEP, IMX471_ANA_GAIN_DEFAULT);
725be1589e5SKate Hsuan 
726be1589e5SKate Hsuan 	v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
727be1589e5SKate Hsuan 			  IMX471_DGTL_GAIN_MIN, IMX471_DGTL_GAIN_MAX,
728be1589e5SKate Hsuan 			  IMX471_DGTL_GAIN_STEP, IMX471_DGTL_GAIN_DEFAULT);
729be1589e5SKate Hsuan 
730be1589e5SKate Hsuan 	v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx471_ctrl_ops,
731be1589e5SKate Hsuan 				     V4L2_CID_TEST_PATTERN,
732be1589e5SKate Hsuan 				     ARRAY_SIZE(imx471_test_pattern_menu) - 1,
733be1589e5SKate Hsuan 				     0, 0, imx471_test_pattern_menu);
734be1589e5SKate Hsuan 
735be1589e5SKate Hsuan 	sensor->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops,
736be1589e5SKate Hsuan 					  V4L2_CID_HFLIP, 0, 1, 1, 0);
737be1589e5SKate Hsuan 
738be1589e5SKate Hsuan 	sensor->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops,
739be1589e5SKate Hsuan 					  V4L2_CID_VFLIP, 0, 1, 1, 0);
740be1589e5SKate Hsuan 
741be1589e5SKate Hsuan 	if (ctrl_hdlr->error) {
742be1589e5SKate Hsuan 		dev_err(sensor->dev, "%s control init failed: %d\n",
743be1589e5SKate Hsuan 			__func__, ctrl_hdlr->error);
744be1589e5SKate Hsuan 		goto error;
745be1589e5SKate Hsuan 	}
746be1589e5SKate Hsuan 
747be1589e5SKate Hsuan 	link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
748be1589e5SKate Hsuan 	sensor->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
749be1589e5SKate Hsuan 	sensor->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
750be1589e5SKate Hsuan 	sensor->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
751be1589e5SKate Hsuan 
752be1589e5SKate Hsuan 	sensor->sd.ctrl_handler = ctrl_hdlr;
753be1589e5SKate Hsuan 
754be1589e5SKate Hsuan 	return 0;
755be1589e5SKate Hsuan 
756be1589e5SKate Hsuan error:
757be1589e5SKate Hsuan 	v4l2_ctrl_handler_free(ctrl_hdlr);
758be1589e5SKate Hsuan 
759be1589e5SKate Hsuan 	return ctrl_hdlr->error;
760be1589e5SKate Hsuan }
761be1589e5SKate Hsuan 
762be1589e5SKate Hsuan static int imx471_check_hwcfg(struct imx471 *sensor)
763be1589e5SKate Hsuan {
764be1589e5SKate Hsuan 	struct v4l2_fwnode_endpoint bus_cfg = {
765be1589e5SKate Hsuan 		.bus_type = V4L2_MBUS_CSI2_DPHY,
766be1589e5SKate Hsuan 	};
767be1589e5SKate Hsuan 	struct fwnode_handle *ep, *fwnode = dev_fwnode(sensor->dev);
768be1589e5SKate Hsuan 	unsigned long link_freq_bitmap;
769be1589e5SKate Hsuan 	struct clk *clk;
770be1589e5SKate Hsuan 	int ret;
771be1589e5SKate Hsuan 
772be1589e5SKate Hsuan 	clk = devm_v4l2_sensor_clk_get(sensor->dev, NULL);
773be1589e5SKate Hsuan 	if (IS_ERR(clk))
774be1589e5SKate Hsuan 		return dev_err_probe(sensor->dev, PTR_ERR(clk),
775be1589e5SKate Hsuan 				     "can't get clock frequency\n");
776be1589e5SKate Hsuan 
777be1589e5SKate Hsuan 	if (clk_get_rate(clk) != IMX471_EXT_CLK)
778be1589e5SKate Hsuan 		return dev_err_probe(sensor->dev, -EINVAL,
779be1589e5SKate Hsuan 				     "external clock %lu is not supported\n",
780be1589e5SKate Hsuan 				     clk_get_rate(clk));
781be1589e5SKate Hsuan 
782be1589e5SKate Hsuan 	ep = fwnode_graph_get_endpoint_by_id(fwnode, 0, 0, 0);
783be1589e5SKate Hsuan 	ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);
784be1589e5SKate Hsuan 	fwnode_handle_put(ep);
785be1589e5SKate Hsuan 	if (ret)
786be1589e5SKate Hsuan 		return dev_err_probe(sensor->dev, ret,
787be1589e5SKate Hsuan 				     "parsing endpoint failed\n");
788be1589e5SKate Hsuan 
789be1589e5SKate Hsuan 	if (bus_cfg.bus.mipi_csi2.num_data_lanes != 4) {
790be1589e5SKate Hsuan 		ret = dev_err_probe(sensor->dev, -EINVAL,
791be1589e5SKate Hsuan 				    "number of CSI2 data lanes %u is not supported\n",
792be1589e5SKate Hsuan 				    bus_cfg.bus.mipi_csi2.num_data_lanes);
793be1589e5SKate Hsuan 		goto done_endpoint_free;
794be1589e5SKate Hsuan 	}
795be1589e5SKate Hsuan 
796be1589e5SKate Hsuan 	ret = v4l2_link_freq_to_bitmap(sensor->dev, bus_cfg.link_frequencies,
797be1589e5SKate Hsuan 				       bus_cfg.nr_of_link_frequencies,
798be1589e5SKate Hsuan 				       link_freq_menu_items,
799be1589e5SKate Hsuan 				       ARRAY_SIZE(link_freq_menu_items),
800be1589e5SKate Hsuan 				       &link_freq_bitmap);
801be1589e5SKate Hsuan 
802be1589e5SKate Hsuan done_endpoint_free:
803be1589e5SKate Hsuan 	v4l2_fwnode_endpoint_free(&bus_cfg);
804be1589e5SKate Hsuan 
805be1589e5SKate Hsuan 	return ret;
806be1589e5SKate Hsuan }
807be1589e5SKate Hsuan 
808be1589e5SKate Hsuan static int imx471_probe(struct i2c_client *client)
809be1589e5SKate Hsuan {
810be1589e5SKate Hsuan 	struct imx471 *sensor;
811be1589e5SKate Hsuan 	int ret;
812be1589e5SKate Hsuan 
813be1589e5SKate Hsuan 	sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL);
814be1589e5SKate Hsuan 	if (!sensor)
815be1589e5SKate Hsuan 		return dev_err_probe(&client->dev, -ENOMEM,
816be1589e5SKate Hsuan 				     "failed to allocate memory\n");
817be1589e5SKate Hsuan 
818be1589e5SKate Hsuan 	sensor->dev = &client->dev;
819be1589e5SKate Hsuan 
820be1589e5SKate Hsuan 	ret = imx471_check_hwcfg(sensor);
821be1589e5SKate Hsuan 	if (ret)
822be1589e5SKate Hsuan 		return dev_err_probe(sensor->dev, ret,
823be1589e5SKate Hsuan 				     "failed to check hwcfg: %d\n", ret);
824be1589e5SKate Hsuan 
825be1589e5SKate Hsuan 	ret = imx471_get_regulators(sensor->dev, sensor);
826be1589e5SKate Hsuan 	if (ret)
827be1589e5SKate Hsuan 		return dev_err_probe(sensor->dev, ret,
828be1589e5SKate Hsuan 				     "failed to get regulators\n");
829be1589e5SKate Hsuan 
830be1589e5SKate Hsuan 	sensor->reset_gpio = devm_gpiod_get_optional(sensor->dev, "reset",
831be1589e5SKate Hsuan 						     GPIOD_OUT_HIGH);
832be1589e5SKate Hsuan 	if (IS_ERR(sensor->reset_gpio))
833be1589e5SKate Hsuan 		return dev_err_probe(sensor->dev, PTR_ERR(sensor->reset_gpio),
834be1589e5SKate Hsuan 				     "failed to get reset gpio\n");
835be1589e5SKate Hsuan 
836be1589e5SKate Hsuan 	sensor->img_clk = devm_v4l2_sensor_clk_get(sensor->dev, NULL);
837be1589e5SKate Hsuan 	if (IS_ERR(sensor->img_clk))
838be1589e5SKate Hsuan 		return dev_err_probe(sensor->dev, PTR_ERR(sensor->img_clk),
839be1589e5SKate Hsuan 				     "failed to get imaging clock\n");
840be1589e5SKate Hsuan 
841be1589e5SKate Hsuan 	v4l2_i2c_subdev_init(&sensor->sd, client, &imx471_subdev_ops);
842be1589e5SKate Hsuan 
843be1589e5SKate Hsuan 	sensor->regmap = devm_cci_regmap_init_i2c(client, 16);
844be1589e5SKate Hsuan 	if (IS_ERR(sensor->regmap))
845be1589e5SKate Hsuan 		return dev_err_probe(sensor->dev, PTR_ERR(sensor->regmap),
846be1589e5SKate Hsuan 				     "failed to initialize CCI\n");
847be1589e5SKate Hsuan 
848be1589e5SKate Hsuan 	ret = imx471_power_on(sensor->dev);
849be1589e5SKate Hsuan 	if (ret)
850be1589e5SKate Hsuan 		return dev_err_probe(sensor->dev, ret,
851be1589e5SKate Hsuan 				     "failed to power on\n");
852be1589e5SKate Hsuan 
853be1589e5SKate Hsuan 	ret = imx471_identify_module(sensor);
854be1589e5SKate Hsuan 	if (ret) {
855be1589e5SKate Hsuan 		dev_err_probe(sensor->dev, ret, "failed to find sensor: %d\n",
856be1589e5SKate Hsuan 			      ret);
857be1589e5SKate Hsuan 		goto error_power_off;
858be1589e5SKate Hsuan 	}
859be1589e5SKate Hsuan 
860be1589e5SKate Hsuan 	ret = imx471_init_controls(sensor);
861be1589e5SKate Hsuan 	if (ret) {
862be1589e5SKate Hsuan 		dev_err_probe(sensor->dev, ret, "failed to init controls: %d\n",
863be1589e5SKate Hsuan 			      ret);
864be1589e5SKate Hsuan 		goto error_power_off;
865be1589e5SKate Hsuan 	}
866be1589e5SKate Hsuan 
867be1589e5SKate Hsuan 	sensor->sd.internal_ops = &imx471_internal_ops;
868be1589e5SKate Hsuan 	sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
869be1589e5SKate Hsuan 	sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
870be1589e5SKate Hsuan 	sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
871be1589e5SKate Hsuan 
872be1589e5SKate Hsuan 	ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
873be1589e5SKate Hsuan 	if (ret) {
874be1589e5SKate Hsuan 		dev_err_probe(sensor->dev, ret,
875be1589e5SKate Hsuan 			      "failed to init entity pads: %d\n", ret);
876be1589e5SKate Hsuan 		goto error_v4l2_ctrl_handler_free;
877be1589e5SKate Hsuan 	}
878be1589e5SKate Hsuan 
879be1589e5SKate Hsuan 	sensor->sd.state_lock = sensor->ctrl_handler.lock;
880be1589e5SKate Hsuan 	ret = v4l2_subdev_init_finalize(&sensor->sd);
881be1589e5SKate Hsuan 	if (ret < 0) {
882be1589e5SKate Hsuan 		dev_err_probe(sensor->dev, ret, "failed to init subdev: %d\n",
883be1589e5SKate Hsuan 			      ret);
884be1589e5SKate Hsuan 		goto error_media_entity_pm;
885be1589e5SKate Hsuan 	}
886be1589e5SKate Hsuan 
887be1589e5SKate Hsuan 	pm_runtime_set_active(sensor->dev);
888be1589e5SKate Hsuan 	pm_runtime_enable(sensor->dev);
889be1589e5SKate Hsuan 
890be1589e5SKate Hsuan 	ret = v4l2_async_register_subdev_sensor(&sensor->sd);
891be1589e5SKate Hsuan 	if (ret < 0)
892be1589e5SKate Hsuan 		goto error_v4l2_subdev_cleanup;
893be1589e5SKate Hsuan 
894be1589e5SKate Hsuan 	pm_runtime_idle(sensor->dev);
895be1589e5SKate Hsuan 
896be1589e5SKate Hsuan 	return 0;
897be1589e5SKate Hsuan 
898be1589e5SKate Hsuan error_v4l2_subdev_cleanup:
899be1589e5SKate Hsuan 	pm_runtime_disable(sensor->dev);
900be1589e5SKate Hsuan 	pm_runtime_set_suspended(sensor->dev);
901be1589e5SKate Hsuan 	v4l2_subdev_cleanup(&sensor->sd);
902be1589e5SKate Hsuan 
903be1589e5SKate Hsuan error_media_entity_pm:
904be1589e5SKate Hsuan 	media_entity_cleanup(&sensor->sd.entity);
905be1589e5SKate Hsuan 
906be1589e5SKate Hsuan error_v4l2_ctrl_handler_free:
907be1589e5SKate Hsuan 	v4l2_ctrl_handler_free(sensor->sd.ctrl_handler);
908be1589e5SKate Hsuan 
909be1589e5SKate Hsuan error_power_off:
910be1589e5SKate Hsuan 	imx471_power_off(sensor->dev);
911be1589e5SKate Hsuan 
912be1589e5SKate Hsuan 	return ret;
913be1589e5SKate Hsuan }
914be1589e5SKate Hsuan 
915be1589e5SKate Hsuan static void imx471_remove(struct i2c_client *client)
916be1589e5SKate Hsuan {
917be1589e5SKate Hsuan 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
918be1589e5SKate Hsuan 
919be1589e5SKate Hsuan 	v4l2_async_unregister_subdev(sd);
920be1589e5SKate Hsuan 	v4l2_subdev_cleanup(sd);
921be1589e5SKate Hsuan 	media_entity_cleanup(&sd->entity);
922be1589e5SKate Hsuan 	v4l2_ctrl_handler_free(sd->ctrl_handler);
923be1589e5SKate Hsuan 
924be1589e5SKate Hsuan 	pm_runtime_disable(&client->dev);
925be1589e5SKate Hsuan 
926be1589e5SKate Hsuan 	if (!pm_runtime_status_suspended(&client->dev)) {
927be1589e5SKate Hsuan 		imx471_power_off(&client->dev);
928be1589e5SKate Hsuan 		pm_runtime_set_suspended(&client->dev);
929be1589e5SKate Hsuan 	}
930be1589e5SKate Hsuan }
931be1589e5SKate Hsuan 
932be1589e5SKate Hsuan static DEFINE_RUNTIME_DEV_PM_OPS(imx471_pm_ops, imx471_power_off,
933be1589e5SKate Hsuan 				 imx471_power_on, NULL);
934be1589e5SKate Hsuan 
935be1589e5SKate Hsuan static const struct acpi_device_id imx471_acpi_ids[] __maybe_unused = {
936be1589e5SKate Hsuan 	{ "SONY471A" },
937be1589e5SKate Hsuan 	{ "TBE20A0" },
938be1589e5SKate Hsuan 	{ /* sentinel */ }
939be1589e5SKate Hsuan };
940be1589e5SKate Hsuan MODULE_DEVICE_TABLE(acpi, imx471_acpi_ids);
941be1589e5SKate Hsuan 
942be1589e5SKate Hsuan static struct i2c_driver imx471_i2c_driver = {
943be1589e5SKate Hsuan 	.driver = {
944be1589e5SKate Hsuan 		.name = "imx471",
945be1589e5SKate Hsuan 		.acpi_match_table = ACPI_PTR(imx471_acpi_ids),
946be1589e5SKate Hsuan 		.pm = pm_sleep_ptr(&imx471_pm_ops),
947be1589e5SKate Hsuan 	},
948be1589e5SKate Hsuan 	.probe = imx471_probe,
949be1589e5SKate Hsuan 	.remove = imx471_remove,
950be1589e5SKate Hsuan };
951be1589e5SKate Hsuan module_i2c_driver(imx471_i2c_driver);
952be1589e5SKate Hsuan 
953be1589e5SKate Hsuan MODULE_AUTHOR("Jimmy Su <jimmy.su@intel.com>");
954be1589e5SKate Hsuan MODULE_AUTHOR("Serin Yeh <serin.yeh@intel.com>");
955be1589e5SKate Hsuan MODULE_AUTHOR("Kate Hsuan <hpa@redhat.com>");
956be1589e5SKate Hsuan MODULE_DESCRIPTION("Sony imx471 sensor driver");
957be1589e5SKate Hsuan MODULE_LICENSE("GPL");
958