xref: /openbmc/linux/drivers/media/i2c/st-vgxy61.c (revision aaeb31c0)
1153e4ad4SBenjamin Mugnier // SPDX-License-Identifier: GPL-2.0
2153e4ad4SBenjamin Mugnier /*
3153e4ad4SBenjamin Mugnier  * Driver for VGXY61 global shutter sensor family driver
4153e4ad4SBenjamin Mugnier  *
5153e4ad4SBenjamin Mugnier  * Copyright (C) 2022 STMicroelectronics SA
6153e4ad4SBenjamin Mugnier  */
7153e4ad4SBenjamin Mugnier 
8153e4ad4SBenjamin Mugnier #include <linux/clk.h>
9153e4ad4SBenjamin Mugnier #include <linux/delay.h>
10153e4ad4SBenjamin Mugnier #include <linux/gpio/consumer.h>
11153e4ad4SBenjamin Mugnier #include <linux/i2c.h>
12153e4ad4SBenjamin Mugnier #include <linux/iopoll.h>
13153e4ad4SBenjamin Mugnier #include <linux/module.h>
14153e4ad4SBenjamin Mugnier #include <linux/pm_runtime.h>
15153e4ad4SBenjamin Mugnier #include <linux/regulator/consumer.h>
16153e4ad4SBenjamin Mugnier #include <linux/units.h>
1751c2bf13SAndy Shevchenko 
1851c2bf13SAndy Shevchenko #include <asm/unaligned.h>
1951c2bf13SAndy Shevchenko 
20153e4ad4SBenjamin Mugnier #include <media/mipi-csi2.h>
21153e4ad4SBenjamin Mugnier #include <media/v4l2-async.h>
22153e4ad4SBenjamin Mugnier #include <media/v4l2-ctrls.h>
23153e4ad4SBenjamin Mugnier #include <media/v4l2-device.h>
24153e4ad4SBenjamin Mugnier #include <media/v4l2-fwnode.h>
25153e4ad4SBenjamin Mugnier #include <media/v4l2-subdev.h>
26153e4ad4SBenjamin Mugnier 
27153e4ad4SBenjamin Mugnier #define VGXY61_REG_8BIT(n)				((1 << 16) | (n))
28153e4ad4SBenjamin Mugnier #define VGXY61_REG_16BIT(n)				((2 << 16) | (n))
29153e4ad4SBenjamin Mugnier #define VGXY61_REG_32BIT(n)				((4 << 16) | (n))
30153e4ad4SBenjamin Mugnier #define VGXY61_REG_SIZE_SHIFT				16
31153e4ad4SBenjamin Mugnier #define VGXY61_REG_ADDR_MASK				0xffff
32153e4ad4SBenjamin Mugnier 
33153e4ad4SBenjamin Mugnier #define VGXY61_REG_MODEL_ID				VGXY61_REG_16BIT(0x0000)
34153e4ad4SBenjamin Mugnier #define VG5661_MODEL_ID					0x5661
35153e4ad4SBenjamin Mugnier #define VG5761_MODEL_ID					0x5761
36153e4ad4SBenjamin Mugnier #define VGXY61_REG_REVISION				VGXY61_REG_16BIT(0x0002)
37153e4ad4SBenjamin Mugnier #define VGXY61_REG_FWPATCH_REVISION			VGXY61_REG_16BIT(0x0014)
38153e4ad4SBenjamin Mugnier #define VGXY61_REG_FWPATCH_START_ADDR			VGXY61_REG_8BIT(0x2000)
39153e4ad4SBenjamin Mugnier #define VGXY61_REG_SYSTEM_FSM				VGXY61_REG_8BIT(0x0020)
40153e4ad4SBenjamin Mugnier #define VGXY61_SYSTEM_FSM_SW_STBY			0x03
41153e4ad4SBenjamin Mugnier #define VGXY61_SYSTEM_FSM_STREAMING			0x04
42153e4ad4SBenjamin Mugnier #define VGXY61_REG_NVM					VGXY61_REG_8BIT(0x0023)
43153e4ad4SBenjamin Mugnier #define VGXY61_NVM_OK					0x04
44153e4ad4SBenjamin Mugnier #define VGXY61_REG_STBY					VGXY61_REG_8BIT(0x0201)
45153e4ad4SBenjamin Mugnier #define VGXY61_STBY_NO_REQ				0
46153e4ad4SBenjamin Mugnier #define VGXY61_STBY_REQ_TMP_READ			BIT(2)
47153e4ad4SBenjamin Mugnier #define VGXY61_REG_STREAMING				VGXY61_REG_8BIT(0x0202)
48153e4ad4SBenjamin Mugnier #define VGXY61_STREAMING_NO_REQ				0
49153e4ad4SBenjamin Mugnier #define VGXY61_STREAMING_REQ_STOP			BIT(0)
50153e4ad4SBenjamin Mugnier #define VGXY61_STREAMING_REQ_START			BIT(1)
51153e4ad4SBenjamin Mugnier #define VGXY61_REG_EXT_CLOCK				VGXY61_REG_32BIT(0x0220)
52153e4ad4SBenjamin Mugnier #define VGXY61_REG_CLK_PLL_PREDIV			VGXY61_REG_8BIT(0x0224)
53153e4ad4SBenjamin Mugnier #define VGXY61_REG_CLK_SYS_PLL_MULT			VGXY61_REG_8BIT(0x0225)
54153e4ad4SBenjamin Mugnier #define VGXY61_REG_GPIO_0_CTRL				VGXY61_REG_8BIT(0x0236)
55153e4ad4SBenjamin Mugnier #define VGXY61_REG_GPIO_1_CTRL				VGXY61_REG_8BIT(0x0237)
56153e4ad4SBenjamin Mugnier #define VGXY61_REG_GPIO_2_CTRL				VGXY61_REG_8BIT(0x0238)
57153e4ad4SBenjamin Mugnier #define VGXY61_REG_GPIO_3_CTRL				VGXY61_REG_8BIT(0x0239)
58153e4ad4SBenjamin Mugnier #define VGXY61_REG_SIGNALS_POLARITY_CTRL		VGXY61_REG_8BIT(0x023b)
59153e4ad4SBenjamin Mugnier #define VGXY61_REG_LINE_LENGTH				VGXY61_REG_16BIT(0x0300)
60153e4ad4SBenjamin Mugnier #define VGXY61_REG_ORIENTATION				VGXY61_REG_8BIT(0x0302)
61153e4ad4SBenjamin Mugnier #define VGXY61_REG_VT_CTRL				VGXY61_REG_8BIT(0x0304)
62153e4ad4SBenjamin Mugnier #define VGXY61_REG_FORMAT_CTRL				VGXY61_REG_8BIT(0x0305)
63153e4ad4SBenjamin Mugnier #define VGXY61_REG_OIF_CTRL				VGXY61_REG_16BIT(0x0306)
64153e4ad4SBenjamin Mugnier #define VGXY61_REG_OIF_ROI0_CTRL			VGXY61_REG_8BIT(0x030a)
65153e4ad4SBenjamin Mugnier #define VGXY61_REG_ROI0_START_H				VGXY61_REG_16BIT(0x0400)
66153e4ad4SBenjamin Mugnier #define VGXY61_REG_ROI0_START_V				VGXY61_REG_16BIT(0x0402)
67153e4ad4SBenjamin Mugnier #define VGXY61_REG_ROI0_END_H				VGXY61_REG_16BIT(0x0404)
68153e4ad4SBenjamin Mugnier #define VGXY61_REG_ROI0_END_V				VGXY61_REG_16BIT(0x0406)
69153e4ad4SBenjamin Mugnier #define VGXY61_REG_PATGEN_CTRL				VGXY61_REG_32BIT(0x0440)
70153e4ad4SBenjamin Mugnier #define VGXY61_PATGEN_LONG_ENABLE			BIT(16)
71153e4ad4SBenjamin Mugnier #define VGXY61_PATGEN_SHORT_ENABLE			BIT(0)
72153e4ad4SBenjamin Mugnier #define VGXY61_PATGEN_LONG_TYPE_SHIFT			18
73153e4ad4SBenjamin Mugnier #define VGXY61_PATGEN_SHORT_TYPE_SHIFT			4
74153e4ad4SBenjamin Mugnier #define VGXY61_REG_FRAME_CONTENT_CTRL			VGXY61_REG_8BIT(0x0478)
75153e4ad4SBenjamin Mugnier #define VGXY61_REG_COARSE_EXPOSURE_LONG			VGXY61_REG_16BIT(0x0500)
76153e4ad4SBenjamin Mugnier #define VGXY61_REG_COARSE_EXPOSURE_SHORT		VGXY61_REG_16BIT(0x0504)
77153e4ad4SBenjamin Mugnier #define VGXY61_REG_ANALOG_GAIN				VGXY61_REG_8BIT(0x0508)
78153e4ad4SBenjamin Mugnier #define VGXY61_REG_DIGITAL_GAIN_LONG			VGXY61_REG_16BIT(0x050a)
79153e4ad4SBenjamin Mugnier #define VGXY61_REG_DIGITAL_GAIN_SHORT			VGXY61_REG_16BIT(0x0512)
80153e4ad4SBenjamin Mugnier #define VGXY61_REG_FRAME_LENGTH				VGXY61_REG_16BIT(0x051a)
81153e4ad4SBenjamin Mugnier #define VGXY61_REG_SIGNALS_CTRL				VGXY61_REG_16BIT(0x0522)
82153e4ad4SBenjamin Mugnier #define VGXY61_SIGNALS_GPIO_ID_SHIFT			4
83153e4ad4SBenjamin Mugnier #define VGXY61_REG_READOUT_CTRL				VGXY61_REG_8BIT(0x0530)
84153e4ad4SBenjamin Mugnier #define VGXY61_REG_HDR_CTRL				VGXY61_REG_8BIT(0x0532)
85153e4ad4SBenjamin Mugnier #define VGXY61_REG_PATGEN_LONG_DATA_GR			VGXY61_REG_16BIT(0x092c)
86153e4ad4SBenjamin Mugnier #define VGXY61_REG_PATGEN_LONG_DATA_R			VGXY61_REG_16BIT(0x092e)
87153e4ad4SBenjamin Mugnier #define VGXY61_REG_PATGEN_LONG_DATA_B			VGXY61_REG_16BIT(0x0930)
88153e4ad4SBenjamin Mugnier #define VGXY61_REG_PATGEN_LONG_DATA_GB			VGXY61_REG_16BIT(0x0932)
89153e4ad4SBenjamin Mugnier #define VGXY61_REG_PATGEN_SHORT_DATA_GR			VGXY61_REG_16BIT(0x0950)
90153e4ad4SBenjamin Mugnier #define VGXY61_REG_PATGEN_SHORT_DATA_R			VGXY61_REG_16BIT(0x0952)
91153e4ad4SBenjamin Mugnier #define VGXY61_REG_PATGEN_SHORT_DATA_B			VGXY61_REG_16BIT(0x0954)
92153e4ad4SBenjamin Mugnier #define VGXY61_REG_PATGEN_SHORT_DATA_GB			VGXY61_REG_16BIT(0x0956)
93153e4ad4SBenjamin Mugnier #define VGXY61_REG_BYPASS_CTRL				VGXY61_REG_8BIT(0x0a60)
94153e4ad4SBenjamin Mugnier 
95153e4ad4SBenjamin Mugnier #define VGX661_WIDTH					1464
96153e4ad4SBenjamin Mugnier #define VGX661_HEIGHT					1104
97153e4ad4SBenjamin Mugnier #define VGX761_WIDTH					1944
98153e4ad4SBenjamin Mugnier #define VGX761_HEIGHT					1204
99153e4ad4SBenjamin Mugnier #define VGX661_DEFAULT_MODE				1
100153e4ad4SBenjamin Mugnier #define VGX761_DEFAULT_MODE				1
101153e4ad4SBenjamin Mugnier #define VGX661_SHORT_ROT_TERM				93
102153e4ad4SBenjamin Mugnier #define VGX761_SHORT_ROT_TERM				90
103153e4ad4SBenjamin Mugnier #define VGXY61_EXPOS_ROT_TERM				66
104153e4ad4SBenjamin Mugnier #define VGXY61_WRITE_MULTIPLE_CHUNK_MAX			16
105153e4ad4SBenjamin Mugnier #define VGXY61_NB_GPIOS					4
106153e4ad4SBenjamin Mugnier #define VGXY61_NB_POLARITIES				5
107153e4ad4SBenjamin Mugnier #define VGXY61_FRAME_LENGTH_DEF				1313
108153e4ad4SBenjamin Mugnier #define VGXY61_MIN_FRAME_LENGTH				1288
109153e4ad4SBenjamin Mugnier #define VGXY61_MIN_EXPOSURE				10
110153e4ad4SBenjamin Mugnier #define VGXY61_HDR_LINEAR_RATIO				10
111153e4ad4SBenjamin Mugnier #define VGXY61_TIMEOUT_MS				500
112153e4ad4SBenjamin Mugnier #define VGXY61_MEDIA_BUS_FMT_DEF			MEDIA_BUS_FMT_Y8_1X8
113153e4ad4SBenjamin Mugnier 
114153e4ad4SBenjamin Mugnier #define VGXY61_FWPATCH_REVISION_MAJOR			2
115153e4ad4SBenjamin Mugnier #define VGXY61_FWPATCH_REVISION_MINOR			0
116153e4ad4SBenjamin Mugnier #define VGXY61_FWPATCH_REVISION_MICRO			5
117153e4ad4SBenjamin Mugnier 
118153e4ad4SBenjamin Mugnier static const u8 patch_array[] = {
119153e4ad4SBenjamin Mugnier 	0xbf, 0x00, 0x05, 0x20, 0x06, 0x01, 0xe0, 0xe0, 0x04, 0x80, 0xe6, 0x45,
120153e4ad4SBenjamin Mugnier 	0xed, 0x6f, 0xfe, 0xff, 0x14, 0x80, 0x1f, 0x84, 0x10, 0x42, 0x05, 0x7c,
121153e4ad4SBenjamin Mugnier 	0x01, 0xc4, 0x1e, 0x80, 0xb6, 0x42, 0x00, 0xe0, 0x1e, 0x82, 0x1e, 0xc0,
122153e4ad4SBenjamin Mugnier 	0x93, 0xdd, 0xc3, 0xc1, 0x0c, 0x04, 0x00, 0xfa, 0x86, 0x0d, 0x70, 0xe1,
123153e4ad4SBenjamin Mugnier 	0x04, 0x98, 0x15, 0x00, 0x28, 0xe0, 0x14, 0x02, 0x08, 0xfc, 0x15, 0x40,
124153e4ad4SBenjamin Mugnier 	0x28, 0xe0, 0x98, 0x58, 0xe0, 0xef, 0x04, 0x98, 0x0e, 0x04, 0x00, 0xf0,
125153e4ad4SBenjamin Mugnier 	0x15, 0x00, 0x28, 0xe0, 0x19, 0xc8, 0x15, 0x40, 0x28, 0xe0, 0xc6, 0x41,
126153e4ad4SBenjamin Mugnier 	0xfc, 0xe0, 0x14, 0x80, 0x1f, 0x84, 0x14, 0x02, 0xa0, 0xfc, 0x1e, 0x80,
127153e4ad4SBenjamin Mugnier 	0x14, 0x80, 0x14, 0x02, 0x80, 0xfb, 0x14, 0x02, 0xe0, 0xfc, 0x1e, 0x80,
128153e4ad4SBenjamin Mugnier 	0x14, 0xc0, 0x1f, 0x84, 0x14, 0x02, 0xa4, 0xfc, 0x1e, 0xc0, 0x14, 0xc0,
129153e4ad4SBenjamin Mugnier 	0x14, 0x02, 0x80, 0xfb, 0x14, 0x02, 0xe4, 0xfc, 0x1e, 0xc0, 0x0c, 0x0c,
130153e4ad4SBenjamin Mugnier 	0x00, 0xf2, 0x93, 0xdd, 0x86, 0x00, 0xf8, 0xe0, 0x04, 0x80, 0xc6, 0x03,
131153e4ad4SBenjamin Mugnier 	0x70, 0xe1, 0x0e, 0x84, 0x93, 0xdd, 0xc3, 0xc1, 0x0c, 0x04, 0x00, 0xfa,
132153e4ad4SBenjamin Mugnier 	0x6b, 0x80, 0x06, 0x40, 0x6c, 0xe1, 0x04, 0x80, 0x09, 0x00, 0xe0, 0xe0,
133153e4ad4SBenjamin Mugnier 	0x0b, 0xa1, 0x95, 0x84, 0x05, 0x0c, 0x1c, 0xe0, 0x86, 0x02, 0xf9, 0x60,
134153e4ad4SBenjamin Mugnier 	0xe0, 0xcf, 0x78, 0x6e, 0x80, 0xef, 0x25, 0x0c, 0x18, 0xe0, 0x05, 0x4c,
135153e4ad4SBenjamin Mugnier 	0x1c, 0xe0, 0x86, 0x02, 0xf9, 0x60, 0xe0, 0xcf, 0x0b, 0x84, 0xd8, 0x6d,
136153e4ad4SBenjamin Mugnier 	0x80, 0xef, 0x05, 0x4c, 0x18, 0xe0, 0x04, 0xd8, 0x0b, 0xa5, 0x95, 0x84,
137153e4ad4SBenjamin Mugnier 	0x05, 0x0c, 0x2c, 0xe0, 0x06, 0x02, 0x01, 0x60, 0xe0, 0xce, 0x18, 0x6d,
138153e4ad4SBenjamin Mugnier 	0x80, 0xef, 0x25, 0x0c, 0x30, 0xe0, 0x05, 0x4c, 0x2c, 0xe0, 0x06, 0x02,
139153e4ad4SBenjamin Mugnier 	0x01, 0x60, 0xe0, 0xce, 0x0b, 0x84, 0x78, 0x6c, 0x80, 0xef, 0x05, 0x4c,
140153e4ad4SBenjamin Mugnier 	0x30, 0xe0, 0x0c, 0x0c, 0x00, 0xf2, 0x93, 0xdd, 0x46, 0x01, 0x70, 0xe1,
141153e4ad4SBenjamin Mugnier 	0x08, 0x80, 0x0b, 0xa1, 0x08, 0x5c, 0x00, 0xda, 0x06, 0x01, 0x68, 0xe1,
142153e4ad4SBenjamin Mugnier 	0x04, 0x80, 0x4a, 0x40, 0x84, 0xe0, 0x08, 0x5c, 0x00, 0x9a, 0x06, 0x01,
143153e4ad4SBenjamin Mugnier 	0xe0, 0xe0, 0x04, 0x80, 0x15, 0x00, 0x60, 0xe0, 0x19, 0xc4, 0x15, 0x40,
144153e4ad4SBenjamin Mugnier 	0x60, 0xe0, 0x15, 0x00, 0x78, 0xe0, 0x19, 0xc4, 0x15, 0x40, 0x78, 0xe0,
145153e4ad4SBenjamin Mugnier 	0x93, 0xdd, 0xc3, 0xc1, 0x46, 0x01, 0x70, 0xe1, 0x08, 0x80, 0x0b, 0xa1,
146153e4ad4SBenjamin Mugnier 	0x08, 0x5c, 0x00, 0xda, 0x06, 0x01, 0x68, 0xe1, 0x04, 0x80, 0x4a, 0x40,
147153e4ad4SBenjamin Mugnier 	0x84, 0xe0, 0x08, 0x5c, 0x00, 0x9a, 0x06, 0x01, 0xe0, 0xe0, 0x14, 0x80,
148153e4ad4SBenjamin Mugnier 	0x25, 0x02, 0x54, 0xe0, 0x29, 0xc4, 0x25, 0x42, 0x54, 0xe0, 0x24, 0x80,
149153e4ad4SBenjamin Mugnier 	0x35, 0x04, 0x6c, 0xe0, 0x39, 0xc4, 0x35, 0x44, 0x6c, 0xe0, 0x25, 0x02,
150153e4ad4SBenjamin Mugnier 	0x64, 0xe0, 0x29, 0xc4, 0x25, 0x42, 0x64, 0xe0, 0x04, 0x80, 0x15, 0x00,
151153e4ad4SBenjamin Mugnier 	0x7c, 0xe0, 0x19, 0xc4, 0x15, 0x40, 0x7c, 0xe0, 0x93, 0xdd, 0xc3, 0xc1,
152153e4ad4SBenjamin Mugnier 	0x4c, 0x04, 0x7c, 0xfa, 0x86, 0x40, 0x98, 0xe0, 0x14, 0x80, 0x1b, 0xa1,
153153e4ad4SBenjamin Mugnier 	0x06, 0x00, 0x00, 0xc0, 0x08, 0x42, 0x38, 0xdc, 0x08, 0x64, 0xa0, 0xef,
154153e4ad4SBenjamin Mugnier 	0x86, 0x42, 0x3c, 0xe0, 0x68, 0x49, 0x80, 0xef, 0x6b, 0x80, 0x78, 0x53,
155153e4ad4SBenjamin Mugnier 	0xc8, 0xef, 0xc6, 0x54, 0x6c, 0xe1, 0x7b, 0x80, 0xb5, 0x14, 0x0c, 0xf8,
156153e4ad4SBenjamin Mugnier 	0x05, 0x14, 0x14, 0xf8, 0x1a, 0xac, 0x8a, 0x80, 0x0b, 0x90, 0x38, 0x55,
157153e4ad4SBenjamin Mugnier 	0x80, 0xef, 0x1a, 0xae, 0x17, 0xc2, 0x03, 0x82, 0x88, 0x65, 0x80, 0xef,
158153e4ad4SBenjamin Mugnier 	0x1b, 0x80, 0x0b, 0x8e, 0x68, 0x65, 0x80, 0xef, 0x9b, 0x80, 0x0b, 0x8c,
159153e4ad4SBenjamin Mugnier 	0x08, 0x65, 0x80, 0xef, 0x6b, 0x80, 0x0b, 0x92, 0x1b, 0x8c, 0x98, 0x64,
160153e4ad4SBenjamin Mugnier 	0x80, 0xef, 0x1a, 0xec, 0x9b, 0x80, 0x0b, 0x90, 0x95, 0x54, 0x10, 0xe0,
161153e4ad4SBenjamin Mugnier 	0xa8, 0x53, 0x80, 0xef, 0x1a, 0xee, 0x17, 0xc2, 0x03, 0x82, 0xf8, 0x63,
162153e4ad4SBenjamin Mugnier 	0x80, 0xef, 0x1b, 0x80, 0x0b, 0x8e, 0xd8, 0x63, 0x80, 0xef, 0x1b, 0x8c,
163153e4ad4SBenjamin Mugnier 	0x68, 0x63, 0x80, 0xef, 0x6b, 0x80, 0x0b, 0x92, 0x65, 0x54, 0x14, 0xe0,
164153e4ad4SBenjamin Mugnier 	0x08, 0x65, 0x84, 0xef, 0x68, 0x63, 0x80, 0xef, 0x7b, 0x80, 0x0b, 0x8c,
165153e4ad4SBenjamin Mugnier 	0xa8, 0x64, 0x84, 0xef, 0x08, 0x63, 0x80, 0xef, 0x14, 0xe8, 0x46, 0x44,
166153e4ad4SBenjamin Mugnier 	0x94, 0xe1, 0x24, 0x88, 0x4a, 0x4e, 0x04, 0xe0, 0x14, 0xea, 0x1a, 0x04,
167153e4ad4SBenjamin Mugnier 	0x08, 0xe0, 0x0a, 0x40, 0x84, 0xed, 0x0c, 0x04, 0x00, 0xe2, 0x4a, 0x40,
168153e4ad4SBenjamin Mugnier 	0x04, 0xe0, 0x19, 0x16, 0xc0, 0xe0, 0x0a, 0x40, 0x84, 0xed, 0x21, 0x54,
169153e4ad4SBenjamin Mugnier 	0x60, 0xe0, 0x0c, 0x04, 0x00, 0xe2, 0x1b, 0xa5, 0x0e, 0xea, 0x01, 0x89,
170153e4ad4SBenjamin Mugnier 	0x21, 0x54, 0x64, 0xe0, 0x7e, 0xe8, 0x65, 0x82, 0x1b, 0xa7, 0x26, 0x00,
171153e4ad4SBenjamin Mugnier 	0x00, 0x80, 0xa5, 0x82, 0x1b, 0xa9, 0x65, 0x82, 0x1b, 0xa3, 0x01, 0x85,
172153e4ad4SBenjamin Mugnier 	0x16, 0x00, 0x00, 0xc0, 0x01, 0x54, 0x04, 0xf8, 0x06, 0xaa, 0x01, 0x83,
173153e4ad4SBenjamin Mugnier 	0x06, 0xa8, 0x65, 0x81, 0x06, 0xa8, 0x01, 0x54, 0x04, 0xf8, 0x01, 0x83,
174153e4ad4SBenjamin Mugnier 	0x06, 0xaa, 0x09, 0x14, 0x18, 0xf8, 0x0b, 0xa1, 0x05, 0x84, 0xc6, 0x42,
175153e4ad4SBenjamin Mugnier 	0xd4, 0xe0, 0x14, 0x84, 0x01, 0x83, 0x01, 0x54, 0x60, 0xe0, 0x01, 0x54,
176153e4ad4SBenjamin Mugnier 	0x64, 0xe0, 0x0b, 0x02, 0x90, 0xe0, 0x10, 0x02, 0x90, 0xe5, 0x01, 0x54,
177153e4ad4SBenjamin Mugnier 	0x88, 0xe0, 0xb5, 0x81, 0xc6, 0x40, 0xd4, 0xe0, 0x14, 0x80, 0x0b, 0x02,
178153e4ad4SBenjamin Mugnier 	0xe0, 0xe4, 0x10, 0x02, 0x31, 0x66, 0x02, 0xc0, 0x01, 0x54, 0x88, 0xe0,
179153e4ad4SBenjamin Mugnier 	0x1a, 0x84, 0x29, 0x14, 0x10, 0xe0, 0x1c, 0xaa, 0x2b, 0xa1, 0xf5, 0x82,
180153e4ad4SBenjamin Mugnier 	0x25, 0x14, 0x10, 0xf8, 0x2b, 0x04, 0xa8, 0xe0, 0x20, 0x44, 0x0d, 0x70,
181153e4ad4SBenjamin Mugnier 	0x03, 0xc0, 0x2b, 0xa1, 0x04, 0x00, 0x80, 0x9a, 0x02, 0x40, 0x84, 0x90,
182153e4ad4SBenjamin Mugnier 	0x03, 0x54, 0x04, 0x80, 0x4c, 0x0c, 0x7c, 0xf2, 0x93, 0xdd, 0x00, 0x00,
183153e4ad4SBenjamin Mugnier 	0x02, 0xa9, 0x00, 0x00, 0x64, 0x4a, 0x40, 0x00, 0x08, 0x2d, 0x58, 0xe0,
184153e4ad4SBenjamin Mugnier 	0xa8, 0x98, 0x40, 0x00, 0x28, 0x07, 0x34, 0xe0, 0x05, 0xb9, 0x00, 0x00,
185153e4ad4SBenjamin Mugnier 	0x28, 0x00, 0x41, 0x05, 0x88, 0x00, 0x41, 0x3c, 0x98, 0x00, 0x41, 0x52,
186153e4ad4SBenjamin Mugnier 	0x04, 0x01, 0x41, 0x79, 0x3c, 0x01, 0x41, 0x6a, 0x3d, 0xfe, 0x00, 0x00,
187153e4ad4SBenjamin Mugnier };
188153e4ad4SBenjamin Mugnier 
189153e4ad4SBenjamin Mugnier static const char * const vgxy61_test_pattern_menu[] = {
190153e4ad4SBenjamin Mugnier 	"Disabled",
191153e4ad4SBenjamin Mugnier 	"Solid",
192153e4ad4SBenjamin Mugnier 	"Colorbar",
193153e4ad4SBenjamin Mugnier 	"Gradbar",
194153e4ad4SBenjamin Mugnier 	"Hgrey",
195153e4ad4SBenjamin Mugnier 	"Vgrey",
196153e4ad4SBenjamin Mugnier 	"Dgrey",
197153e4ad4SBenjamin Mugnier 	"PN28",
198153e4ad4SBenjamin Mugnier };
199153e4ad4SBenjamin Mugnier 
200153e4ad4SBenjamin Mugnier static const char * const vgxy61_hdr_mode_menu[] = {
201153e4ad4SBenjamin Mugnier 	"HDR linearize",
202153e4ad4SBenjamin Mugnier 	"HDR substraction",
203153e4ad4SBenjamin Mugnier 	"No HDR",
204153e4ad4SBenjamin Mugnier };
205153e4ad4SBenjamin Mugnier 
206153e4ad4SBenjamin Mugnier static const char * const vgxy61_supply_name[] = {
207153e4ad4SBenjamin Mugnier 	"VCORE",
208153e4ad4SBenjamin Mugnier 	"VDDIO",
209153e4ad4SBenjamin Mugnier 	"VANA",
210153e4ad4SBenjamin Mugnier };
211153e4ad4SBenjamin Mugnier 
212153e4ad4SBenjamin Mugnier static const s64 link_freq[] = {
213153e4ad4SBenjamin Mugnier 	/*
214153e4ad4SBenjamin Mugnier 	 * MIPI output freq is 804Mhz / 2, as it uses both rising edge and
215153e4ad4SBenjamin Mugnier 	 * falling edges to send data
216153e4ad4SBenjamin Mugnier 	 */
217153e4ad4SBenjamin Mugnier 	402000000ULL
218153e4ad4SBenjamin Mugnier };
219153e4ad4SBenjamin Mugnier 
220153e4ad4SBenjamin Mugnier enum vgxy61_bin_mode {
221153e4ad4SBenjamin Mugnier 	VGXY61_BIN_MODE_NORMAL,
222153e4ad4SBenjamin Mugnier 	VGXY61_BIN_MODE_DIGITAL_X2,
223153e4ad4SBenjamin Mugnier 	VGXY61_BIN_MODE_DIGITAL_X4,
224153e4ad4SBenjamin Mugnier };
225153e4ad4SBenjamin Mugnier 
226153e4ad4SBenjamin Mugnier enum vgxy61_hdr_mode {
227153e4ad4SBenjamin Mugnier 	VGXY61_HDR_LINEAR,
228153e4ad4SBenjamin Mugnier 	VGXY61_HDR_SUB,
229153e4ad4SBenjamin Mugnier 	VGXY61_NO_HDR,
230153e4ad4SBenjamin Mugnier };
231153e4ad4SBenjamin Mugnier 
232153e4ad4SBenjamin Mugnier enum vgxy61_strobe_mode {
233153e4ad4SBenjamin Mugnier 	VGXY61_STROBE_DISABLED,
234153e4ad4SBenjamin Mugnier 	VGXY61_STROBE_LONG,
235153e4ad4SBenjamin Mugnier 	VGXY61_STROBE_ENABLED,
236153e4ad4SBenjamin Mugnier };
237153e4ad4SBenjamin Mugnier 
238153e4ad4SBenjamin Mugnier struct vgxy61_mode_info {
239153e4ad4SBenjamin Mugnier 	u32 width;
240153e4ad4SBenjamin Mugnier 	u32 height;
241153e4ad4SBenjamin Mugnier 	enum vgxy61_bin_mode bin_mode;
242153e4ad4SBenjamin Mugnier 	struct v4l2_rect crop;
243153e4ad4SBenjamin Mugnier };
244153e4ad4SBenjamin Mugnier 
245153e4ad4SBenjamin Mugnier struct vgxy61_fmt_desc {
246153e4ad4SBenjamin Mugnier 	u32 code;
247153e4ad4SBenjamin Mugnier 	u8 bpp;
248153e4ad4SBenjamin Mugnier 	u8 data_type;
249153e4ad4SBenjamin Mugnier };
250153e4ad4SBenjamin Mugnier 
251153e4ad4SBenjamin Mugnier static const struct vgxy61_fmt_desc vgxy61_supported_codes[] = {
252153e4ad4SBenjamin Mugnier 	{
253153e4ad4SBenjamin Mugnier 		.code = MEDIA_BUS_FMT_Y8_1X8,
254153e4ad4SBenjamin Mugnier 		.bpp = 8,
255153e4ad4SBenjamin Mugnier 		.data_type = MIPI_CSI2_DT_RAW8,
256153e4ad4SBenjamin Mugnier 	},
257153e4ad4SBenjamin Mugnier 	{
258153e4ad4SBenjamin Mugnier 		.code = MEDIA_BUS_FMT_Y10_1X10,
259153e4ad4SBenjamin Mugnier 		.bpp = 10,
260153e4ad4SBenjamin Mugnier 		.data_type = MIPI_CSI2_DT_RAW10,
261153e4ad4SBenjamin Mugnier 	},
262153e4ad4SBenjamin Mugnier 	{
263153e4ad4SBenjamin Mugnier 		.code = MEDIA_BUS_FMT_Y12_1X12,
264153e4ad4SBenjamin Mugnier 		.bpp = 12,
265153e4ad4SBenjamin Mugnier 		.data_type = MIPI_CSI2_DT_RAW12,
266153e4ad4SBenjamin Mugnier 	},
267153e4ad4SBenjamin Mugnier 	{
268153e4ad4SBenjamin Mugnier 		.code = MEDIA_BUS_FMT_Y14_1X14,
269153e4ad4SBenjamin Mugnier 		.bpp = 14,
270153e4ad4SBenjamin Mugnier 		.data_type = MIPI_CSI2_DT_RAW14,
271153e4ad4SBenjamin Mugnier 	},
272153e4ad4SBenjamin Mugnier 	{
273153e4ad4SBenjamin Mugnier 		.code = MEDIA_BUS_FMT_Y16_1X16,
274153e4ad4SBenjamin Mugnier 		.bpp = 16,
275153e4ad4SBenjamin Mugnier 		.data_type = MIPI_CSI2_DT_RAW16,
276153e4ad4SBenjamin Mugnier 	},
277153e4ad4SBenjamin Mugnier };
278153e4ad4SBenjamin Mugnier 
279153e4ad4SBenjamin Mugnier static const struct vgxy61_mode_info vgx661_mode_data[] = {
280153e4ad4SBenjamin Mugnier 	{
281153e4ad4SBenjamin Mugnier 		.width = VGX661_WIDTH,
282153e4ad4SBenjamin Mugnier 		.height = VGX661_HEIGHT,
283153e4ad4SBenjamin Mugnier 		.bin_mode = VGXY61_BIN_MODE_NORMAL,
284153e4ad4SBenjamin Mugnier 		.crop = {
285153e4ad4SBenjamin Mugnier 			.left = 0,
286153e4ad4SBenjamin Mugnier 			.top = 0,
287153e4ad4SBenjamin Mugnier 			.width = VGX661_WIDTH,
288153e4ad4SBenjamin Mugnier 			.height = VGX661_HEIGHT,
289153e4ad4SBenjamin Mugnier 		},
290153e4ad4SBenjamin Mugnier 	},
291153e4ad4SBenjamin Mugnier 	{
292153e4ad4SBenjamin Mugnier 		.width = 1280,
293153e4ad4SBenjamin Mugnier 		.height = 720,
294153e4ad4SBenjamin Mugnier 		.bin_mode = VGXY61_BIN_MODE_NORMAL,
295153e4ad4SBenjamin Mugnier 		.crop = {
296153e4ad4SBenjamin Mugnier 			.left = 92,
297153e4ad4SBenjamin Mugnier 			.top = 192,
298153e4ad4SBenjamin Mugnier 			.width = 1280,
299153e4ad4SBenjamin Mugnier 			.height = 720,
300153e4ad4SBenjamin Mugnier 		},
301153e4ad4SBenjamin Mugnier 	},
302153e4ad4SBenjamin Mugnier 	{
303153e4ad4SBenjamin Mugnier 		.width = 640,
304153e4ad4SBenjamin Mugnier 		.height = 480,
305153e4ad4SBenjamin Mugnier 		.bin_mode = VGXY61_BIN_MODE_DIGITAL_X2,
306153e4ad4SBenjamin Mugnier 		.crop = {
307153e4ad4SBenjamin Mugnier 			.left = 92,
308153e4ad4SBenjamin Mugnier 			.top = 72,
309153e4ad4SBenjamin Mugnier 			.width = 1280,
310153e4ad4SBenjamin Mugnier 			.height = 960,
311153e4ad4SBenjamin Mugnier 		},
312153e4ad4SBenjamin Mugnier 	},
313153e4ad4SBenjamin Mugnier 	{
314153e4ad4SBenjamin Mugnier 		.width = 320,
315153e4ad4SBenjamin Mugnier 		.height = 240,
316153e4ad4SBenjamin Mugnier 		.bin_mode = VGXY61_BIN_MODE_DIGITAL_X4,
317153e4ad4SBenjamin Mugnier 		.crop = {
318153e4ad4SBenjamin Mugnier 			.left = 92,
319153e4ad4SBenjamin Mugnier 			.top = 72,
320153e4ad4SBenjamin Mugnier 			.width = 1280,
321153e4ad4SBenjamin Mugnier 			.height = 960,
322153e4ad4SBenjamin Mugnier 		},
323153e4ad4SBenjamin Mugnier 	},
324153e4ad4SBenjamin Mugnier };
325153e4ad4SBenjamin Mugnier 
326153e4ad4SBenjamin Mugnier static const struct vgxy61_mode_info vgx761_mode_data[] = {
327153e4ad4SBenjamin Mugnier 	{
328153e4ad4SBenjamin Mugnier 		.width = VGX761_WIDTH,
329153e4ad4SBenjamin Mugnier 		.height = VGX761_HEIGHT,
330153e4ad4SBenjamin Mugnier 		.bin_mode = VGXY61_BIN_MODE_NORMAL,
331153e4ad4SBenjamin Mugnier 		.crop = {
332153e4ad4SBenjamin Mugnier 			.left = 0,
333153e4ad4SBenjamin Mugnier 			.top = 0,
334153e4ad4SBenjamin Mugnier 			.width = VGX761_WIDTH,
335153e4ad4SBenjamin Mugnier 			.height = VGX761_HEIGHT,
336153e4ad4SBenjamin Mugnier 		},
337153e4ad4SBenjamin Mugnier 	},
338153e4ad4SBenjamin Mugnier 	{
339153e4ad4SBenjamin Mugnier 		.width = 1920,
340153e4ad4SBenjamin Mugnier 		.height = 1080,
341153e4ad4SBenjamin Mugnier 		.bin_mode = VGXY61_BIN_MODE_NORMAL,
342153e4ad4SBenjamin Mugnier 		.crop = {
343153e4ad4SBenjamin Mugnier 			.left = 12,
344153e4ad4SBenjamin Mugnier 			.top = 62,
345153e4ad4SBenjamin Mugnier 			.width = 1920,
346153e4ad4SBenjamin Mugnier 			.height = 1080,
347153e4ad4SBenjamin Mugnier 		},
348153e4ad4SBenjamin Mugnier 	},
349153e4ad4SBenjamin Mugnier 	{
350153e4ad4SBenjamin Mugnier 		.width = 1280,
351153e4ad4SBenjamin Mugnier 		.height = 720,
352153e4ad4SBenjamin Mugnier 		.bin_mode = VGXY61_BIN_MODE_NORMAL,
353153e4ad4SBenjamin Mugnier 		.crop = {
354153e4ad4SBenjamin Mugnier 			.left = 332,
355153e4ad4SBenjamin Mugnier 			.top = 242,
356153e4ad4SBenjamin Mugnier 			.width = 1280,
357153e4ad4SBenjamin Mugnier 			.height = 720,
358153e4ad4SBenjamin Mugnier 		},
359153e4ad4SBenjamin Mugnier 	},
360153e4ad4SBenjamin Mugnier 	{
361153e4ad4SBenjamin Mugnier 		.width = 640,
362153e4ad4SBenjamin Mugnier 		.height = 480,
363153e4ad4SBenjamin Mugnier 		.bin_mode = VGXY61_BIN_MODE_DIGITAL_X2,
364153e4ad4SBenjamin Mugnier 		.crop = {
365153e4ad4SBenjamin Mugnier 			.left = 332,
366153e4ad4SBenjamin Mugnier 			.top = 122,
367153e4ad4SBenjamin Mugnier 			.width = 1280,
368153e4ad4SBenjamin Mugnier 			.height = 960,
369153e4ad4SBenjamin Mugnier 		},
370153e4ad4SBenjamin Mugnier 	},
371153e4ad4SBenjamin Mugnier 	{
372153e4ad4SBenjamin Mugnier 		.width = 320,
373153e4ad4SBenjamin Mugnier 		.height = 240,
374153e4ad4SBenjamin Mugnier 		.bin_mode = VGXY61_BIN_MODE_DIGITAL_X4,
375153e4ad4SBenjamin Mugnier 		.crop = {
376153e4ad4SBenjamin Mugnier 			.left = 332,
377153e4ad4SBenjamin Mugnier 			.top = 122,
378153e4ad4SBenjamin Mugnier 			.width = 1280,
379153e4ad4SBenjamin Mugnier 			.height = 960,
380153e4ad4SBenjamin Mugnier 		},
381153e4ad4SBenjamin Mugnier 	},
382153e4ad4SBenjamin Mugnier };
383153e4ad4SBenjamin Mugnier 
384153e4ad4SBenjamin Mugnier struct vgxy61_dev {
385153e4ad4SBenjamin Mugnier 	struct i2c_client *i2c_client;
386153e4ad4SBenjamin Mugnier 	struct v4l2_subdev sd;
387153e4ad4SBenjamin Mugnier 	struct media_pad pad;
388153e4ad4SBenjamin Mugnier 	struct regulator_bulk_data supplies[ARRAY_SIZE(vgxy61_supply_name)];
389153e4ad4SBenjamin Mugnier 	struct gpio_desc *reset_gpio;
390153e4ad4SBenjamin Mugnier 	struct clk *xclk;
391153e4ad4SBenjamin Mugnier 	u32 clk_freq;
392153e4ad4SBenjamin Mugnier 	u16 id;
393153e4ad4SBenjamin Mugnier 	u16 sensor_width;
394153e4ad4SBenjamin Mugnier 	u16 sensor_height;
395153e4ad4SBenjamin Mugnier 	u16 oif_ctrl;
396153e4ad4SBenjamin Mugnier 	unsigned int nb_of_lane;
397153e4ad4SBenjamin Mugnier 	u32 data_rate_in_mbps;
398153e4ad4SBenjamin Mugnier 	u32 pclk;
399153e4ad4SBenjamin Mugnier 	u16 line_length;
400153e4ad4SBenjamin Mugnier 	u16 rot_term;
401153e4ad4SBenjamin Mugnier 	bool gpios_polarity;
402153e4ad4SBenjamin Mugnier 	/* Lock to protect all members below */
403153e4ad4SBenjamin Mugnier 	struct mutex lock;
404153e4ad4SBenjamin Mugnier 	struct v4l2_ctrl_handler ctrl_handler;
405153e4ad4SBenjamin Mugnier 	struct v4l2_ctrl *pixel_rate_ctrl;
406153e4ad4SBenjamin Mugnier 	struct v4l2_ctrl *expo_ctrl;
407153e4ad4SBenjamin Mugnier 	struct v4l2_ctrl *vblank_ctrl;
408153e4ad4SBenjamin Mugnier 	struct v4l2_ctrl *vflip_ctrl;
409153e4ad4SBenjamin Mugnier 	struct v4l2_ctrl *hflip_ctrl;
410153e4ad4SBenjamin Mugnier 	bool streaming;
411153e4ad4SBenjamin Mugnier 	struct v4l2_mbus_framefmt fmt;
412153e4ad4SBenjamin Mugnier 	const struct vgxy61_mode_info *sensor_modes;
413153e4ad4SBenjamin Mugnier 	unsigned int sensor_modes_nb;
414153e4ad4SBenjamin Mugnier 	const struct vgxy61_mode_info *default_mode;
415153e4ad4SBenjamin Mugnier 	const struct vgxy61_mode_info *current_mode;
416153e4ad4SBenjamin Mugnier 	bool hflip;
417153e4ad4SBenjamin Mugnier 	bool vflip;
418153e4ad4SBenjamin Mugnier 	enum vgxy61_hdr_mode hdr;
419153e4ad4SBenjamin Mugnier 	u16 expo_long;
420153e4ad4SBenjamin Mugnier 	u16 expo_short;
421153e4ad4SBenjamin Mugnier 	u16 expo_max;
422153e4ad4SBenjamin Mugnier 	u16 expo_min;
423153e4ad4SBenjamin Mugnier 	u16 vblank;
424153e4ad4SBenjamin Mugnier 	u16 vblank_min;
425153e4ad4SBenjamin Mugnier 	u16 frame_length;
426153e4ad4SBenjamin Mugnier 	u16 digital_gain;
427153e4ad4SBenjamin Mugnier 	u8 analog_gain;
428153e4ad4SBenjamin Mugnier 	enum vgxy61_strobe_mode strobe_mode;
429153e4ad4SBenjamin Mugnier 	u32 pattern;
430153e4ad4SBenjamin Mugnier };
431153e4ad4SBenjamin Mugnier 
get_bpp_by_code(__u32 code)432153e4ad4SBenjamin Mugnier static u8 get_bpp_by_code(__u32 code)
433153e4ad4SBenjamin Mugnier {
434153e4ad4SBenjamin Mugnier 	unsigned int i;
435153e4ad4SBenjamin Mugnier 
436153e4ad4SBenjamin Mugnier 	for (i = 0; i < ARRAY_SIZE(vgxy61_supported_codes); i++) {
437153e4ad4SBenjamin Mugnier 		if (vgxy61_supported_codes[i].code == code)
438153e4ad4SBenjamin Mugnier 			return vgxy61_supported_codes[i].bpp;
439153e4ad4SBenjamin Mugnier 	}
440153e4ad4SBenjamin Mugnier 	/* Should never happen */
441153e4ad4SBenjamin Mugnier 	WARN(1, "Unsupported code %d. default to 8 bpp", code);
442153e4ad4SBenjamin Mugnier 	return 8;
443153e4ad4SBenjamin Mugnier }
444153e4ad4SBenjamin Mugnier 
get_data_type_by_code(__u32 code)445153e4ad4SBenjamin Mugnier static u8 get_data_type_by_code(__u32 code)
446153e4ad4SBenjamin Mugnier {
447153e4ad4SBenjamin Mugnier 	unsigned int i;
448153e4ad4SBenjamin Mugnier 
449153e4ad4SBenjamin Mugnier 	for (i = 0; i < ARRAY_SIZE(vgxy61_supported_codes); i++) {
450153e4ad4SBenjamin Mugnier 		if (vgxy61_supported_codes[i].code == code)
451153e4ad4SBenjamin Mugnier 			return vgxy61_supported_codes[i].data_type;
452153e4ad4SBenjamin Mugnier 	}
453153e4ad4SBenjamin Mugnier 	/* Should never happen */
454153e4ad4SBenjamin Mugnier 	WARN(1, "Unsupported code %d. default to MIPI_CSI2_DT_RAW8 data type",
455153e4ad4SBenjamin Mugnier 	     code);
456153e4ad4SBenjamin Mugnier 	return MIPI_CSI2_DT_RAW8;
457153e4ad4SBenjamin Mugnier }
458153e4ad4SBenjamin Mugnier 
compute_pll_parameters_by_freq(u32 freq,u8 * prediv,u8 * mult)459153e4ad4SBenjamin Mugnier static void compute_pll_parameters_by_freq(u32 freq, u8 *prediv, u8 *mult)
460153e4ad4SBenjamin Mugnier {
461153e4ad4SBenjamin Mugnier 	const unsigned int predivs[] = {1, 2, 4};
462153e4ad4SBenjamin Mugnier 	unsigned int i;
463153e4ad4SBenjamin Mugnier 
464153e4ad4SBenjamin Mugnier 	/*
465153e4ad4SBenjamin Mugnier 	 * Freq range is [6Mhz-27Mhz] already checked.
466153e4ad4SBenjamin Mugnier 	 * Output of divider should be in [6Mhz-12Mhz[.
467153e4ad4SBenjamin Mugnier 	 */
468153e4ad4SBenjamin Mugnier 	for (i = 0; i < ARRAY_SIZE(predivs); i++) {
469153e4ad4SBenjamin Mugnier 		*prediv = predivs[i];
470153e4ad4SBenjamin Mugnier 		if (freq / *prediv < 12 * HZ_PER_MHZ)
471153e4ad4SBenjamin Mugnier 			break;
472153e4ad4SBenjamin Mugnier 	}
473153e4ad4SBenjamin Mugnier 	WARN_ON(i == ARRAY_SIZE(predivs));
474153e4ad4SBenjamin Mugnier 
475153e4ad4SBenjamin Mugnier 	/*
476153e4ad4SBenjamin Mugnier 	 * Target freq is 804Mhz. Don't change this as it will impact image
477153e4ad4SBenjamin Mugnier 	 * quality.
478153e4ad4SBenjamin Mugnier 	 */
479153e4ad4SBenjamin Mugnier 	*mult = ((804 * HZ_PER_MHZ) * (*prediv) + freq / 2) / freq;
480153e4ad4SBenjamin Mugnier }
481153e4ad4SBenjamin Mugnier 
get_pixel_rate(struct vgxy61_dev * sensor)482153e4ad4SBenjamin Mugnier static s32 get_pixel_rate(struct vgxy61_dev *sensor)
483153e4ad4SBenjamin Mugnier {
484153e4ad4SBenjamin Mugnier 	return div64_u64((u64)sensor->data_rate_in_mbps * sensor->nb_of_lane,
485153e4ad4SBenjamin Mugnier 			 get_bpp_by_code(sensor->fmt.code));
486153e4ad4SBenjamin Mugnier }
487153e4ad4SBenjamin Mugnier 
to_vgxy61_dev(struct v4l2_subdev * sd)488153e4ad4SBenjamin Mugnier static inline struct vgxy61_dev *to_vgxy61_dev(struct v4l2_subdev *sd)
489153e4ad4SBenjamin Mugnier {
490153e4ad4SBenjamin Mugnier 	return container_of(sd, struct vgxy61_dev, sd);
491153e4ad4SBenjamin Mugnier }
492153e4ad4SBenjamin Mugnier 
ctrl_to_sd(struct v4l2_ctrl * ctrl)493153e4ad4SBenjamin Mugnier static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
494153e4ad4SBenjamin Mugnier {
495153e4ad4SBenjamin Mugnier 	return &container_of(ctrl->handler, struct vgxy61_dev,
496153e4ad4SBenjamin Mugnier 			     ctrl_handler)->sd;
497153e4ad4SBenjamin Mugnier }
498153e4ad4SBenjamin Mugnier 
get_chunk_size(struct vgxy61_dev * sensor)499153e4ad4SBenjamin Mugnier static unsigned int get_chunk_size(struct vgxy61_dev *sensor)
500153e4ad4SBenjamin Mugnier {
501153e4ad4SBenjamin Mugnier 	struct i2c_adapter *adapter = sensor->i2c_client->adapter;
502153e4ad4SBenjamin Mugnier 	int max_write_len = VGXY61_WRITE_MULTIPLE_CHUNK_MAX;
503153e4ad4SBenjamin Mugnier 
504153e4ad4SBenjamin Mugnier 	if (adapter->quirks && adapter->quirks->max_write_len)
505153e4ad4SBenjamin Mugnier 		max_write_len = adapter->quirks->max_write_len - 2;
506153e4ad4SBenjamin Mugnier 
507153e4ad4SBenjamin Mugnier 	max_write_len = min(max_write_len, VGXY61_WRITE_MULTIPLE_CHUNK_MAX);
508153e4ad4SBenjamin Mugnier 
509153e4ad4SBenjamin Mugnier 	return max(max_write_len, 1);
510153e4ad4SBenjamin Mugnier }
511153e4ad4SBenjamin Mugnier 
vgxy61_read_multiple(struct vgxy61_dev * sensor,u32 reg,unsigned int len)512153e4ad4SBenjamin Mugnier static int vgxy61_read_multiple(struct vgxy61_dev *sensor, u32 reg,
513153e4ad4SBenjamin Mugnier 				unsigned int len)
514153e4ad4SBenjamin Mugnier {
515153e4ad4SBenjamin Mugnier 	struct i2c_client *client = sensor->i2c_client;
516153e4ad4SBenjamin Mugnier 	struct i2c_msg msg[2];
517153e4ad4SBenjamin Mugnier 	u8 buf[2];
518153e4ad4SBenjamin Mugnier 	u8 val[sizeof(u32)] = {0};
519153e4ad4SBenjamin Mugnier 	int ret;
520153e4ad4SBenjamin Mugnier 
521153e4ad4SBenjamin Mugnier 	if (len > sizeof(u32))
522153e4ad4SBenjamin Mugnier 		return -EINVAL;
523153e4ad4SBenjamin Mugnier 	buf[0] = reg >> 8;
524153e4ad4SBenjamin Mugnier 	buf[1] = reg & 0xff;
525153e4ad4SBenjamin Mugnier 
526153e4ad4SBenjamin Mugnier 	msg[0].addr = client->addr;
527153e4ad4SBenjamin Mugnier 	msg[0].flags = client->flags;
528153e4ad4SBenjamin Mugnier 	msg[0].buf = buf;
529153e4ad4SBenjamin Mugnier 	msg[0].len = sizeof(buf);
530153e4ad4SBenjamin Mugnier 
531153e4ad4SBenjamin Mugnier 	msg[1].addr = client->addr;
532153e4ad4SBenjamin Mugnier 	msg[1].flags = client->flags | I2C_M_RD;
533153e4ad4SBenjamin Mugnier 	msg[1].buf = val;
534153e4ad4SBenjamin Mugnier 	msg[1].len = len;
535153e4ad4SBenjamin Mugnier 
536153e4ad4SBenjamin Mugnier 	ret = i2c_transfer(client->adapter, msg, 2);
537153e4ad4SBenjamin Mugnier 	if (ret < 0) {
538153e4ad4SBenjamin Mugnier 		dev_dbg(&client->dev, "%s: %x i2c_transfer, reg: %x => %d\n",
539153e4ad4SBenjamin Mugnier 			__func__, client->addr, reg, ret);
540153e4ad4SBenjamin Mugnier 		return ret;
541153e4ad4SBenjamin Mugnier 	}
542153e4ad4SBenjamin Mugnier 
543153e4ad4SBenjamin Mugnier 	return get_unaligned_le32(val);
544153e4ad4SBenjamin Mugnier }
545153e4ad4SBenjamin Mugnier 
vgxy61_read_reg(struct vgxy61_dev * sensor,u32 reg)546153e4ad4SBenjamin Mugnier static inline int vgxy61_read_reg(struct vgxy61_dev *sensor, u32 reg)
547153e4ad4SBenjamin Mugnier {
548153e4ad4SBenjamin Mugnier 	return vgxy61_read_multiple(sensor, reg & VGXY61_REG_ADDR_MASK,
549153e4ad4SBenjamin Mugnier 				     (reg >> VGXY61_REG_SIZE_SHIFT) & 7);
550153e4ad4SBenjamin Mugnier }
551153e4ad4SBenjamin Mugnier 
vgxy61_write_multiple(struct vgxy61_dev * sensor,u32 reg,const u8 * data,unsigned int len,int * err)552153e4ad4SBenjamin Mugnier static int vgxy61_write_multiple(struct vgxy61_dev *sensor, u32 reg,
553153e4ad4SBenjamin Mugnier 				 const u8 *data, unsigned int len, int *err)
554153e4ad4SBenjamin Mugnier {
555153e4ad4SBenjamin Mugnier 	struct i2c_client *client = sensor->i2c_client;
556153e4ad4SBenjamin Mugnier 	struct i2c_msg msg;
557153e4ad4SBenjamin Mugnier 	u8 buf[VGXY61_WRITE_MULTIPLE_CHUNK_MAX + 2];
558153e4ad4SBenjamin Mugnier 	unsigned int i;
559153e4ad4SBenjamin Mugnier 	int ret;
560153e4ad4SBenjamin Mugnier 
561153e4ad4SBenjamin Mugnier 	if (err && *err)
562153e4ad4SBenjamin Mugnier 		return *err;
563153e4ad4SBenjamin Mugnier 
564153e4ad4SBenjamin Mugnier 	if (len > VGXY61_WRITE_MULTIPLE_CHUNK_MAX)
565153e4ad4SBenjamin Mugnier 		return -EINVAL;
566153e4ad4SBenjamin Mugnier 	buf[0] = reg >> 8;
567153e4ad4SBenjamin Mugnier 	buf[1] = reg & 0xff;
568153e4ad4SBenjamin Mugnier 	for (i = 0; i < len; i++)
569153e4ad4SBenjamin Mugnier 		buf[i + 2] = data[i];
570153e4ad4SBenjamin Mugnier 
571153e4ad4SBenjamin Mugnier 	msg.addr = client->addr;
572153e4ad4SBenjamin Mugnier 	msg.flags = client->flags;
573153e4ad4SBenjamin Mugnier 	msg.buf = buf;
574153e4ad4SBenjamin Mugnier 	msg.len = len + 2;
575153e4ad4SBenjamin Mugnier 
576153e4ad4SBenjamin Mugnier 	ret = i2c_transfer(client->adapter, &msg, 1);
577153e4ad4SBenjamin Mugnier 	if (ret < 0) {
578153e4ad4SBenjamin Mugnier 		dev_dbg(&client->dev, "%s: i2c_transfer, reg: %x => %d\n",
579153e4ad4SBenjamin Mugnier 			__func__, reg, ret);
580153e4ad4SBenjamin Mugnier 		if (err)
581153e4ad4SBenjamin Mugnier 			*err = ret;
582153e4ad4SBenjamin Mugnier 		return ret;
583153e4ad4SBenjamin Mugnier 	}
584153e4ad4SBenjamin Mugnier 
585153e4ad4SBenjamin Mugnier 	return 0;
586153e4ad4SBenjamin Mugnier }
587153e4ad4SBenjamin Mugnier 
vgxy61_write_array(struct vgxy61_dev * sensor,u32 reg,unsigned int nb,const u8 * array)588153e4ad4SBenjamin Mugnier static int vgxy61_write_array(struct vgxy61_dev *sensor, u32 reg,
589153e4ad4SBenjamin Mugnier 			      unsigned int nb, const u8 *array)
590153e4ad4SBenjamin Mugnier {
591153e4ad4SBenjamin Mugnier 	const unsigned int chunk_size = get_chunk_size(sensor);
592153e4ad4SBenjamin Mugnier 	int ret;
593153e4ad4SBenjamin Mugnier 	unsigned int sz;
594153e4ad4SBenjamin Mugnier 
595153e4ad4SBenjamin Mugnier 	while (nb) {
596153e4ad4SBenjamin Mugnier 		sz = min(nb, chunk_size);
597153e4ad4SBenjamin Mugnier 		ret = vgxy61_write_multiple(sensor, reg, array, sz, NULL);
598153e4ad4SBenjamin Mugnier 		if (ret < 0)
599153e4ad4SBenjamin Mugnier 			return ret;
600153e4ad4SBenjamin Mugnier 		nb -= sz;
601153e4ad4SBenjamin Mugnier 		reg += sz;
602153e4ad4SBenjamin Mugnier 		array += sz;
603153e4ad4SBenjamin Mugnier 	}
604153e4ad4SBenjamin Mugnier 
605153e4ad4SBenjamin Mugnier 	return 0;
606153e4ad4SBenjamin Mugnier }
607153e4ad4SBenjamin Mugnier 
vgxy61_write_reg(struct vgxy61_dev * sensor,u32 reg,u32 val,int * err)608153e4ad4SBenjamin Mugnier static inline int vgxy61_write_reg(struct vgxy61_dev *sensor, u32 reg, u32 val,
609153e4ad4SBenjamin Mugnier 				   int *err)
610153e4ad4SBenjamin Mugnier {
611153e4ad4SBenjamin Mugnier 	return vgxy61_write_multiple(sensor, reg & VGXY61_REG_ADDR_MASK,
612153e4ad4SBenjamin Mugnier 				     (u8 *)&val,
613153e4ad4SBenjamin Mugnier 				     (reg >> VGXY61_REG_SIZE_SHIFT) & 7, err);
614153e4ad4SBenjamin Mugnier }
615153e4ad4SBenjamin Mugnier 
vgxy61_poll_reg(struct vgxy61_dev * sensor,u32 reg,u8 poll_val,unsigned int timeout_ms)616153e4ad4SBenjamin Mugnier static int vgxy61_poll_reg(struct vgxy61_dev *sensor, u32 reg, u8 poll_val,
617153e4ad4SBenjamin Mugnier 			   unsigned int timeout_ms)
618153e4ad4SBenjamin Mugnier {
619153e4ad4SBenjamin Mugnier 	const unsigned int loop_delay_ms = 10;
620153e4ad4SBenjamin Mugnier 	int ret;
621153e4ad4SBenjamin Mugnier 
622153e4ad4SBenjamin Mugnier 	return read_poll_timeout(vgxy61_read_reg, ret,
623153e4ad4SBenjamin Mugnier 				 ((ret < 0) || (ret == poll_val)),
624153e4ad4SBenjamin Mugnier 				 loop_delay_ms * 1000, timeout_ms * 1000,
625153e4ad4SBenjamin Mugnier 				 false, sensor, reg);
626153e4ad4SBenjamin Mugnier }
627153e4ad4SBenjamin Mugnier 
vgxy61_wait_state(struct vgxy61_dev * sensor,int state,unsigned int timeout_ms)628153e4ad4SBenjamin Mugnier static int vgxy61_wait_state(struct vgxy61_dev *sensor, int state,
629153e4ad4SBenjamin Mugnier 			     unsigned int timeout_ms)
630153e4ad4SBenjamin Mugnier {
631153e4ad4SBenjamin Mugnier 	return vgxy61_poll_reg(sensor, VGXY61_REG_SYSTEM_FSM, state,
632153e4ad4SBenjamin Mugnier 			       timeout_ms);
633153e4ad4SBenjamin Mugnier }
634153e4ad4SBenjamin Mugnier 
vgxy61_check_bw(struct vgxy61_dev * sensor)635153e4ad4SBenjamin Mugnier static int vgxy61_check_bw(struct vgxy61_dev *sensor)
636153e4ad4SBenjamin Mugnier {
637153e4ad4SBenjamin Mugnier 	/*
638153e4ad4SBenjamin Mugnier 	 * Simplification of time needed to send short packets and for the MIPI
639153e4ad4SBenjamin Mugnier 	 * to add transition times (EoT, LPS, and SoT packet delimiters) needed
640153e4ad4SBenjamin Mugnier 	 * by the protocol to go in low power between 2 packets of data. This
641153e4ad4SBenjamin Mugnier 	 * is a mipi IP constant for the sensor.
642153e4ad4SBenjamin Mugnier 	 */
643153e4ad4SBenjamin Mugnier 	const unsigned int mipi_margin = 1056;
644153e4ad4SBenjamin Mugnier 	unsigned int binning_scale = sensor->current_mode->crop.height /
645153e4ad4SBenjamin Mugnier 				     sensor->current_mode->height;
646153e4ad4SBenjamin Mugnier 	u8 bpp = get_bpp_by_code(sensor->fmt.code);
647153e4ad4SBenjamin Mugnier 	unsigned int max_bit_per_line;
648153e4ad4SBenjamin Mugnier 	unsigned int bit_per_line;
649153e4ad4SBenjamin Mugnier 	u64 line_rate;
650153e4ad4SBenjamin Mugnier 
651153e4ad4SBenjamin Mugnier 	line_rate = sensor->nb_of_lane * (u64)sensor->data_rate_in_mbps *
652153e4ad4SBenjamin Mugnier 		    sensor->line_length;
653153e4ad4SBenjamin Mugnier 	max_bit_per_line = div64_u64(line_rate, sensor->pclk) - mipi_margin;
654153e4ad4SBenjamin Mugnier 	bit_per_line = (bpp * sensor->current_mode->width) / binning_scale;
655153e4ad4SBenjamin Mugnier 
656153e4ad4SBenjamin Mugnier 	return bit_per_line > max_bit_per_line ? -EINVAL : 0;
657153e4ad4SBenjamin Mugnier }
658153e4ad4SBenjamin Mugnier 
vgxy61_apply_exposure(struct vgxy61_dev * sensor)659153e4ad4SBenjamin Mugnier static int vgxy61_apply_exposure(struct vgxy61_dev *sensor)
660153e4ad4SBenjamin Mugnier {
661153e4ad4SBenjamin Mugnier 	int ret = 0;
662153e4ad4SBenjamin Mugnier 
663153e4ad4SBenjamin Mugnier 	 /* We first set expo to zero to avoid forbidden parameters couple */
664153e4ad4SBenjamin Mugnier 	vgxy61_write_reg(sensor, VGXY61_REG_COARSE_EXPOSURE_SHORT, 0, &ret);
665153e4ad4SBenjamin Mugnier 	vgxy61_write_reg(sensor, VGXY61_REG_COARSE_EXPOSURE_LONG,
666153e4ad4SBenjamin Mugnier 			 sensor->expo_long, &ret);
667153e4ad4SBenjamin Mugnier 	vgxy61_write_reg(sensor, VGXY61_REG_COARSE_EXPOSURE_SHORT,
668153e4ad4SBenjamin Mugnier 			 sensor->expo_short, &ret);
669153e4ad4SBenjamin Mugnier 
670153e4ad4SBenjamin Mugnier 	return ret;
671153e4ad4SBenjamin Mugnier }
672153e4ad4SBenjamin Mugnier 
vgxy61_get_regulators(struct vgxy61_dev * sensor)673153e4ad4SBenjamin Mugnier static int vgxy61_get_regulators(struct vgxy61_dev *sensor)
674153e4ad4SBenjamin Mugnier {
675153e4ad4SBenjamin Mugnier 	unsigned int i;
676153e4ad4SBenjamin Mugnier 
677153e4ad4SBenjamin Mugnier 	for (i = 0; i < ARRAY_SIZE(vgxy61_supply_name); i++)
678153e4ad4SBenjamin Mugnier 		sensor->supplies[i].supply = vgxy61_supply_name[i];
679153e4ad4SBenjamin Mugnier 
680153e4ad4SBenjamin Mugnier 	return devm_regulator_bulk_get(&sensor->i2c_client->dev,
681153e4ad4SBenjamin Mugnier 				       ARRAY_SIZE(vgxy61_supply_name),
682153e4ad4SBenjamin Mugnier 				       sensor->supplies);
683153e4ad4SBenjamin Mugnier }
684153e4ad4SBenjamin Mugnier 
vgxy61_apply_reset(struct vgxy61_dev * sensor)685153e4ad4SBenjamin Mugnier static int vgxy61_apply_reset(struct vgxy61_dev *sensor)
686153e4ad4SBenjamin Mugnier {
687153e4ad4SBenjamin Mugnier 	gpiod_set_value_cansleep(sensor->reset_gpio, 0);
688153e4ad4SBenjamin Mugnier 	usleep_range(5000, 10000);
689153e4ad4SBenjamin Mugnier 	gpiod_set_value_cansleep(sensor->reset_gpio, 1);
690153e4ad4SBenjamin Mugnier 	usleep_range(5000, 10000);
691153e4ad4SBenjamin Mugnier 	gpiod_set_value_cansleep(sensor->reset_gpio, 0);
692153e4ad4SBenjamin Mugnier 	usleep_range(40000, 100000);
693153e4ad4SBenjamin Mugnier 	return vgxy61_wait_state(sensor, VGXY61_SYSTEM_FSM_SW_STBY,
694153e4ad4SBenjamin Mugnier 				 VGXY61_TIMEOUT_MS);
695153e4ad4SBenjamin Mugnier }
696153e4ad4SBenjamin Mugnier 
vgxy61_fill_framefmt(struct vgxy61_dev * sensor,const struct vgxy61_mode_info * mode,struct v4l2_mbus_framefmt * fmt,u32 code)697153e4ad4SBenjamin Mugnier static void vgxy61_fill_framefmt(struct vgxy61_dev *sensor,
698153e4ad4SBenjamin Mugnier 				 const struct vgxy61_mode_info *mode,
699153e4ad4SBenjamin Mugnier 				 struct v4l2_mbus_framefmt *fmt, u32 code)
700153e4ad4SBenjamin Mugnier {
701153e4ad4SBenjamin Mugnier 	fmt->code = code;
702153e4ad4SBenjamin Mugnier 	fmt->width = mode->width;
703153e4ad4SBenjamin Mugnier 	fmt->height = mode->height;
704153e4ad4SBenjamin Mugnier 	fmt->colorspace = V4L2_COLORSPACE_RAW;
705153e4ad4SBenjamin Mugnier 	fmt->field = V4L2_FIELD_NONE;
706153e4ad4SBenjamin Mugnier 	fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
707153e4ad4SBenjamin Mugnier 	fmt->quantization = V4L2_QUANTIZATION_DEFAULT;
708153e4ad4SBenjamin Mugnier 	fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT;
709153e4ad4SBenjamin Mugnier }
710153e4ad4SBenjamin Mugnier 
vgxy61_try_fmt_internal(struct v4l2_subdev * sd,struct v4l2_mbus_framefmt * fmt,const struct vgxy61_mode_info ** new_mode)711153e4ad4SBenjamin Mugnier static int vgxy61_try_fmt_internal(struct v4l2_subdev *sd,
712153e4ad4SBenjamin Mugnier 				   struct v4l2_mbus_framefmt *fmt,
713153e4ad4SBenjamin Mugnier 				   const struct vgxy61_mode_info **new_mode)
714153e4ad4SBenjamin Mugnier {
715153e4ad4SBenjamin Mugnier 	struct vgxy61_dev *sensor = to_vgxy61_dev(sd);
716153e4ad4SBenjamin Mugnier 	const struct vgxy61_mode_info *mode = sensor->sensor_modes;
717153e4ad4SBenjamin Mugnier 	unsigned int index;
718153e4ad4SBenjamin Mugnier 
719153e4ad4SBenjamin Mugnier 	for (index = 0; index < ARRAY_SIZE(vgxy61_supported_codes); index++) {
720153e4ad4SBenjamin Mugnier 		if (vgxy61_supported_codes[index].code == fmt->code)
721153e4ad4SBenjamin Mugnier 			break;
722153e4ad4SBenjamin Mugnier 	}
723153e4ad4SBenjamin Mugnier 	if (index == ARRAY_SIZE(vgxy61_supported_codes))
724153e4ad4SBenjamin Mugnier 		index = 0;
725153e4ad4SBenjamin Mugnier 
726153e4ad4SBenjamin Mugnier 	mode = v4l2_find_nearest_size(sensor->sensor_modes,
727153e4ad4SBenjamin Mugnier 				      sensor->sensor_modes_nb, width, height,
728153e4ad4SBenjamin Mugnier 				      fmt->width, fmt->height);
729153e4ad4SBenjamin Mugnier 	if (new_mode)
730153e4ad4SBenjamin Mugnier 		*new_mode = mode;
731153e4ad4SBenjamin Mugnier 
732153e4ad4SBenjamin Mugnier 	vgxy61_fill_framefmt(sensor, mode, fmt,
733153e4ad4SBenjamin Mugnier 			     vgxy61_supported_codes[index].code);
734153e4ad4SBenjamin Mugnier 
735153e4ad4SBenjamin Mugnier 	return 0;
736153e4ad4SBenjamin Mugnier }
737153e4ad4SBenjamin Mugnier 
vgxy61_get_selection(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_selection * sel)738153e4ad4SBenjamin Mugnier static int vgxy61_get_selection(struct v4l2_subdev *sd,
739153e4ad4SBenjamin Mugnier 				struct v4l2_subdev_state *sd_state,
740153e4ad4SBenjamin Mugnier 				struct v4l2_subdev_selection *sel)
741153e4ad4SBenjamin Mugnier {
742153e4ad4SBenjamin Mugnier 	struct vgxy61_dev *sensor = to_vgxy61_dev(sd);
743153e4ad4SBenjamin Mugnier 
744153e4ad4SBenjamin Mugnier 	switch (sel->target) {
745153e4ad4SBenjamin Mugnier 	case V4L2_SEL_TGT_CROP:
746153e4ad4SBenjamin Mugnier 		sel->r = sensor->current_mode->crop;
747153e4ad4SBenjamin Mugnier 		return 0;
748153e4ad4SBenjamin Mugnier 	case V4L2_SEL_TGT_NATIVE_SIZE:
749153e4ad4SBenjamin Mugnier 	case V4L2_SEL_TGT_CROP_DEFAULT:
750153e4ad4SBenjamin Mugnier 	case V4L2_SEL_TGT_CROP_BOUNDS:
751153e4ad4SBenjamin Mugnier 		sel->r.top = 0;
752153e4ad4SBenjamin Mugnier 		sel->r.left = 0;
753153e4ad4SBenjamin Mugnier 		sel->r.width = sensor->sensor_width;
754153e4ad4SBenjamin Mugnier 		sel->r.height = sensor->sensor_height;
755153e4ad4SBenjamin Mugnier 		return 0;
756153e4ad4SBenjamin Mugnier 	}
757153e4ad4SBenjamin Mugnier 
758153e4ad4SBenjamin Mugnier 	return -EINVAL;
759153e4ad4SBenjamin Mugnier }
760153e4ad4SBenjamin Mugnier 
vgxy61_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_mbus_code_enum * code)761153e4ad4SBenjamin Mugnier static int vgxy61_enum_mbus_code(struct v4l2_subdev *sd,
762153e4ad4SBenjamin Mugnier 				 struct v4l2_subdev_state *sd_state,
763153e4ad4SBenjamin Mugnier 				 struct v4l2_subdev_mbus_code_enum *code)
764153e4ad4SBenjamin Mugnier {
765153e4ad4SBenjamin Mugnier 	if (code->index >= ARRAY_SIZE(vgxy61_supported_codes))
766153e4ad4SBenjamin Mugnier 		return -EINVAL;
767153e4ad4SBenjamin Mugnier 
768153e4ad4SBenjamin Mugnier 	code->code = vgxy61_supported_codes[code->index].code;
769153e4ad4SBenjamin Mugnier 
770153e4ad4SBenjamin Mugnier 	return 0;
771153e4ad4SBenjamin Mugnier }
772153e4ad4SBenjamin Mugnier 
vgxy61_get_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * format)773153e4ad4SBenjamin Mugnier static int vgxy61_get_fmt(struct v4l2_subdev *sd,
774153e4ad4SBenjamin Mugnier 			  struct v4l2_subdev_state *sd_state,
775153e4ad4SBenjamin Mugnier 			  struct v4l2_subdev_format *format)
776153e4ad4SBenjamin Mugnier {
777153e4ad4SBenjamin Mugnier 	struct vgxy61_dev *sensor = to_vgxy61_dev(sd);
778153e4ad4SBenjamin Mugnier 	struct v4l2_mbus_framefmt *fmt;
779153e4ad4SBenjamin Mugnier 
780153e4ad4SBenjamin Mugnier 	mutex_lock(&sensor->lock);
781153e4ad4SBenjamin Mugnier 
782153e4ad4SBenjamin Mugnier 	if (format->which == V4L2_SUBDEV_FORMAT_TRY)
783153e4ad4SBenjamin Mugnier 		fmt = v4l2_subdev_get_try_format(&sensor->sd, sd_state,
784153e4ad4SBenjamin Mugnier 						 format->pad);
785153e4ad4SBenjamin Mugnier 	else
786153e4ad4SBenjamin Mugnier 		fmt = &sensor->fmt;
787153e4ad4SBenjamin Mugnier 
788153e4ad4SBenjamin Mugnier 	format->format = *fmt;
789153e4ad4SBenjamin Mugnier 
790153e4ad4SBenjamin Mugnier 	mutex_unlock(&sensor->lock);
791153e4ad4SBenjamin Mugnier 
792153e4ad4SBenjamin Mugnier 	return 0;
793153e4ad4SBenjamin Mugnier }
794153e4ad4SBenjamin Mugnier 
vgxy61_get_vblank_min(struct vgxy61_dev * sensor,enum vgxy61_hdr_mode hdr)795153e4ad4SBenjamin Mugnier static u16 vgxy61_get_vblank_min(struct vgxy61_dev *sensor,
796153e4ad4SBenjamin Mugnier 				 enum vgxy61_hdr_mode hdr)
797153e4ad4SBenjamin Mugnier {
798153e4ad4SBenjamin Mugnier 	u16 min_vblank =  VGXY61_MIN_FRAME_LENGTH -
799153e4ad4SBenjamin Mugnier 			  sensor->current_mode->crop.height;
800153e4ad4SBenjamin Mugnier 	/* Ensure the first rule of thumb can't be negative */
801153e4ad4SBenjamin Mugnier 	u16 min_vblank_hdr =  VGXY61_MIN_EXPOSURE + sensor->rot_term + 1;
802153e4ad4SBenjamin Mugnier 
803153e4ad4SBenjamin Mugnier 	if (hdr != VGXY61_NO_HDR)
804153e4ad4SBenjamin Mugnier 		return max(min_vblank, min_vblank_hdr);
805153e4ad4SBenjamin Mugnier 	return min_vblank;
806153e4ad4SBenjamin Mugnier }
807153e4ad4SBenjamin Mugnier 
vgxy61_enum_frame_size(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_frame_size_enum * fse)808153e4ad4SBenjamin Mugnier static int vgxy61_enum_frame_size(struct v4l2_subdev *sd,
809153e4ad4SBenjamin Mugnier 				  struct v4l2_subdev_state *sd_state,
810153e4ad4SBenjamin Mugnier 				  struct v4l2_subdev_frame_size_enum *fse)
811153e4ad4SBenjamin Mugnier {
812153e4ad4SBenjamin Mugnier 	struct vgxy61_dev *sensor = to_vgxy61_dev(sd);
813153e4ad4SBenjamin Mugnier 
814153e4ad4SBenjamin Mugnier 	if (fse->index >= sensor->sensor_modes_nb)
815153e4ad4SBenjamin Mugnier 		return -EINVAL;
816153e4ad4SBenjamin Mugnier 
817153e4ad4SBenjamin Mugnier 	fse->min_width = sensor->sensor_modes[fse->index].width;
818153e4ad4SBenjamin Mugnier 	fse->max_width = fse->min_width;
819153e4ad4SBenjamin Mugnier 	fse->min_height = sensor->sensor_modes[fse->index].height;
820153e4ad4SBenjamin Mugnier 	fse->max_height = fse->min_height;
821153e4ad4SBenjamin Mugnier 
822153e4ad4SBenjamin Mugnier 	return 0;
823153e4ad4SBenjamin Mugnier }
824153e4ad4SBenjamin Mugnier 
vgxy61_update_analog_gain(struct vgxy61_dev * sensor,u32 target)825153e4ad4SBenjamin Mugnier static int vgxy61_update_analog_gain(struct vgxy61_dev *sensor, u32 target)
826153e4ad4SBenjamin Mugnier {
827153e4ad4SBenjamin Mugnier 	sensor->analog_gain = target;
828153e4ad4SBenjamin Mugnier 
829153e4ad4SBenjamin Mugnier 	if (sensor->streaming)
830153e4ad4SBenjamin Mugnier 		return vgxy61_write_reg(sensor, VGXY61_REG_ANALOG_GAIN, target,
831153e4ad4SBenjamin Mugnier 					NULL);
832153e4ad4SBenjamin Mugnier 	return 0;
833153e4ad4SBenjamin Mugnier }
834153e4ad4SBenjamin Mugnier 
vgxy61_apply_digital_gain(struct vgxy61_dev * sensor,u32 digital_gain)835153e4ad4SBenjamin Mugnier static int vgxy61_apply_digital_gain(struct vgxy61_dev *sensor,
836153e4ad4SBenjamin Mugnier 				     u32 digital_gain)
837153e4ad4SBenjamin Mugnier {
838153e4ad4SBenjamin Mugnier 	int ret = 0;
839153e4ad4SBenjamin Mugnier 
840153e4ad4SBenjamin Mugnier 	/*
841153e4ad4SBenjamin Mugnier 	 * For a monochrome version, configuring DIGITAL_GAIN_LONG_CH0 and
842153e4ad4SBenjamin Mugnier 	 * DIGITAL_GAIN_SHORT_CH0 is enough to configure the gain of all
843153e4ad4SBenjamin Mugnier 	 * four sub pixels.
844153e4ad4SBenjamin Mugnier 	 */
845153e4ad4SBenjamin Mugnier 	vgxy61_write_reg(sensor, VGXY61_REG_DIGITAL_GAIN_LONG, digital_gain,
846153e4ad4SBenjamin Mugnier 			 &ret);
847153e4ad4SBenjamin Mugnier 	vgxy61_write_reg(sensor, VGXY61_REG_DIGITAL_GAIN_SHORT, digital_gain,
848153e4ad4SBenjamin Mugnier 			 &ret);
849153e4ad4SBenjamin Mugnier 
850153e4ad4SBenjamin Mugnier 	return ret;
851153e4ad4SBenjamin Mugnier }
852153e4ad4SBenjamin Mugnier 
vgxy61_update_digital_gain(struct vgxy61_dev * sensor,u32 target)853153e4ad4SBenjamin Mugnier static int vgxy61_update_digital_gain(struct vgxy61_dev *sensor, u32 target)
854153e4ad4SBenjamin Mugnier {
855153e4ad4SBenjamin Mugnier 	sensor->digital_gain = target;
856153e4ad4SBenjamin Mugnier 
857153e4ad4SBenjamin Mugnier 	if (sensor->streaming)
858153e4ad4SBenjamin Mugnier 		return vgxy61_apply_digital_gain(sensor, sensor->digital_gain);
859153e4ad4SBenjamin Mugnier 	return 0;
860153e4ad4SBenjamin Mugnier }
861153e4ad4SBenjamin Mugnier 
vgxy61_apply_patgen(struct vgxy61_dev * sensor,u32 index)862153e4ad4SBenjamin Mugnier static int vgxy61_apply_patgen(struct vgxy61_dev *sensor, u32 index)
863153e4ad4SBenjamin Mugnier {
864153e4ad4SBenjamin Mugnier 	static const u8 index2val[] = {
865153e4ad4SBenjamin Mugnier 		0x0, 0x1, 0x2, 0x3, 0x10, 0x11, 0x12, 0x13
866153e4ad4SBenjamin Mugnier 	};
867153e4ad4SBenjamin Mugnier 	u32 pattern = index2val[index];
868153e4ad4SBenjamin Mugnier 	u32 reg = (pattern << VGXY61_PATGEN_LONG_TYPE_SHIFT) |
869153e4ad4SBenjamin Mugnier 	      (pattern << VGXY61_PATGEN_SHORT_TYPE_SHIFT);
870153e4ad4SBenjamin Mugnier 
871153e4ad4SBenjamin Mugnier 	if (pattern)
872153e4ad4SBenjamin Mugnier 		reg |= VGXY61_PATGEN_LONG_ENABLE | VGXY61_PATGEN_SHORT_ENABLE;
873153e4ad4SBenjamin Mugnier 	return vgxy61_write_reg(sensor, VGXY61_REG_PATGEN_CTRL, reg, NULL);
874153e4ad4SBenjamin Mugnier }
875153e4ad4SBenjamin Mugnier 
vgxy61_update_patgen(struct vgxy61_dev * sensor,u32 pattern)876153e4ad4SBenjamin Mugnier static int vgxy61_update_patgen(struct vgxy61_dev *sensor, u32 pattern)
877153e4ad4SBenjamin Mugnier {
878153e4ad4SBenjamin Mugnier 	sensor->pattern = pattern;
879153e4ad4SBenjamin Mugnier 
880153e4ad4SBenjamin Mugnier 	if (sensor->streaming)
881153e4ad4SBenjamin Mugnier 		return vgxy61_apply_patgen(sensor, sensor->pattern);
882153e4ad4SBenjamin Mugnier 	return 0;
883153e4ad4SBenjamin Mugnier }
884153e4ad4SBenjamin Mugnier 
vgxy61_apply_gpiox_strobe_mode(struct vgxy61_dev * sensor,enum vgxy61_strobe_mode mode,unsigned int idx)885153e4ad4SBenjamin Mugnier static int vgxy61_apply_gpiox_strobe_mode(struct vgxy61_dev *sensor,
886153e4ad4SBenjamin Mugnier 					  enum vgxy61_strobe_mode mode,
887153e4ad4SBenjamin Mugnier 					  unsigned int idx)
888153e4ad4SBenjamin Mugnier {
889153e4ad4SBenjamin Mugnier 	static const u8 index2val[] = {0x0, 0x1, 0x3};
890483af3feSBenjamin Mugnier 	int reg;
891153e4ad4SBenjamin Mugnier 
892153e4ad4SBenjamin Mugnier 	reg = vgxy61_read_reg(sensor, VGXY61_REG_SIGNALS_CTRL);
893153e4ad4SBenjamin Mugnier 	if (reg < 0)
894153e4ad4SBenjamin Mugnier 		return reg;
895153e4ad4SBenjamin Mugnier 	reg &= ~(0xf << (idx * VGXY61_SIGNALS_GPIO_ID_SHIFT));
896153e4ad4SBenjamin Mugnier 	reg |= index2val[mode] << (idx * VGXY61_SIGNALS_GPIO_ID_SHIFT);
897153e4ad4SBenjamin Mugnier 
898153e4ad4SBenjamin Mugnier 	return vgxy61_write_reg(sensor, VGXY61_REG_SIGNALS_CTRL, reg, NULL);
899153e4ad4SBenjamin Mugnier }
900153e4ad4SBenjamin Mugnier 
vgxy61_update_gpios_strobe_mode(struct vgxy61_dev * sensor,enum vgxy61_hdr_mode hdr)901153e4ad4SBenjamin Mugnier static int vgxy61_update_gpios_strobe_mode(struct vgxy61_dev *sensor,
902153e4ad4SBenjamin Mugnier 					   enum vgxy61_hdr_mode hdr)
903153e4ad4SBenjamin Mugnier {
904153e4ad4SBenjamin Mugnier 	unsigned int i;
905153e4ad4SBenjamin Mugnier 	int ret;
906153e4ad4SBenjamin Mugnier 
907153e4ad4SBenjamin Mugnier 	switch (hdr) {
908153e4ad4SBenjamin Mugnier 	case VGXY61_HDR_LINEAR:
909153e4ad4SBenjamin Mugnier 		sensor->strobe_mode = VGXY61_STROBE_ENABLED;
910153e4ad4SBenjamin Mugnier 		break;
911153e4ad4SBenjamin Mugnier 	case VGXY61_HDR_SUB:
912153e4ad4SBenjamin Mugnier 	case VGXY61_NO_HDR:
913153e4ad4SBenjamin Mugnier 		sensor->strobe_mode = VGXY61_STROBE_LONG;
914153e4ad4SBenjamin Mugnier 		break;
915153e4ad4SBenjamin Mugnier 	default:
916153e4ad4SBenjamin Mugnier 		/* Should never happen */
917153e4ad4SBenjamin Mugnier 		WARN_ON(true);
918153e4ad4SBenjamin Mugnier 		break;
919153e4ad4SBenjamin Mugnier 	}
920153e4ad4SBenjamin Mugnier 
921153e4ad4SBenjamin Mugnier 	if (!sensor->streaming)
922153e4ad4SBenjamin Mugnier 		return 0;
923153e4ad4SBenjamin Mugnier 
924153e4ad4SBenjamin Mugnier 	for (i = 0; i < VGXY61_NB_GPIOS; i++) {
925153e4ad4SBenjamin Mugnier 		ret = vgxy61_apply_gpiox_strobe_mode(sensor,
926153e4ad4SBenjamin Mugnier 						     sensor->strobe_mode,
927153e4ad4SBenjamin Mugnier 						     i);
928153e4ad4SBenjamin Mugnier 		if (ret)
929153e4ad4SBenjamin Mugnier 			return ret;
930153e4ad4SBenjamin Mugnier 	}
931153e4ad4SBenjamin Mugnier 
932153e4ad4SBenjamin Mugnier 	return 0;
933153e4ad4SBenjamin Mugnier }
934153e4ad4SBenjamin Mugnier 
vgxy61_update_gpios_strobe_polarity(struct vgxy61_dev * sensor,bool polarity)935153e4ad4SBenjamin Mugnier static int vgxy61_update_gpios_strobe_polarity(struct vgxy61_dev *sensor,
936153e4ad4SBenjamin Mugnier 					       bool polarity)
937153e4ad4SBenjamin Mugnier {
938153e4ad4SBenjamin Mugnier 	int ret = 0;
939153e4ad4SBenjamin Mugnier 
940153e4ad4SBenjamin Mugnier 	if (sensor->streaming)
941153e4ad4SBenjamin Mugnier 		return -EBUSY;
942153e4ad4SBenjamin Mugnier 
943153e4ad4SBenjamin Mugnier 	vgxy61_write_reg(sensor, VGXY61_REG_GPIO_0_CTRL, polarity << 1, &ret);
944153e4ad4SBenjamin Mugnier 	vgxy61_write_reg(sensor, VGXY61_REG_GPIO_1_CTRL, polarity << 1, &ret);
945153e4ad4SBenjamin Mugnier 	vgxy61_write_reg(sensor, VGXY61_REG_GPIO_2_CTRL, polarity << 1, &ret);
946153e4ad4SBenjamin Mugnier 	vgxy61_write_reg(sensor, VGXY61_REG_GPIO_3_CTRL, polarity << 1, &ret);
947153e4ad4SBenjamin Mugnier 	vgxy61_write_reg(sensor, VGXY61_REG_SIGNALS_POLARITY_CTRL, polarity,
948153e4ad4SBenjamin Mugnier 			 &ret);
949153e4ad4SBenjamin Mugnier 
950153e4ad4SBenjamin Mugnier 	return ret;
951153e4ad4SBenjamin Mugnier }
952153e4ad4SBenjamin Mugnier 
vgxy61_get_expo_long_max(struct vgxy61_dev * sensor,unsigned int short_expo_ratio)953153e4ad4SBenjamin Mugnier static u32 vgxy61_get_expo_long_max(struct vgxy61_dev *sensor,
954153e4ad4SBenjamin Mugnier 				    unsigned int short_expo_ratio)
955153e4ad4SBenjamin Mugnier {
956153e4ad4SBenjamin Mugnier 	u32 first_rot_max_expo, second_rot_max_expo, third_rot_max_expo;
957153e4ad4SBenjamin Mugnier 
958153e4ad4SBenjamin Mugnier 	/* Apply sensor's rules of thumb */
959153e4ad4SBenjamin Mugnier 	/*
960153e4ad4SBenjamin Mugnier 	 * Short exposure + height must be less than frame length to avoid bad
961153e4ad4SBenjamin Mugnier 	 * pixel line at the botom of the image
962153e4ad4SBenjamin Mugnier 	 */
963153e4ad4SBenjamin Mugnier 	first_rot_max_expo =
964153e4ad4SBenjamin Mugnier 		((sensor->frame_length - sensor->current_mode->crop.height -
965153e4ad4SBenjamin Mugnier 		sensor->rot_term) * short_expo_ratio) - 1;
966153e4ad4SBenjamin Mugnier 
967153e4ad4SBenjamin Mugnier 	/*
968153e4ad4SBenjamin Mugnier 	 * Total exposition time must be less than frame length to avoid sensor
969153e4ad4SBenjamin Mugnier 	 * crash
970153e4ad4SBenjamin Mugnier 	 */
971153e4ad4SBenjamin Mugnier 	second_rot_max_expo =
972153e4ad4SBenjamin Mugnier 		(((sensor->frame_length - VGXY61_EXPOS_ROT_TERM) *
973153e4ad4SBenjamin Mugnier 		short_expo_ratio) / (short_expo_ratio + 1)) - 1;
974153e4ad4SBenjamin Mugnier 
975153e4ad4SBenjamin Mugnier 	/*
976153e4ad4SBenjamin Mugnier 	 * Short exposure times 71 must be less than frame length to avoid
977153e4ad4SBenjamin Mugnier 	 * sensor crash
978153e4ad4SBenjamin Mugnier 	 */
979153e4ad4SBenjamin Mugnier 	third_rot_max_expo = (sensor->frame_length / 71) * short_expo_ratio;
980153e4ad4SBenjamin Mugnier 
981153e4ad4SBenjamin Mugnier 	/* Take the minimum from all rules */
982153e4ad4SBenjamin Mugnier 	return min(min(first_rot_max_expo, second_rot_max_expo),
983153e4ad4SBenjamin Mugnier 		   third_rot_max_expo);
984153e4ad4SBenjamin Mugnier }
985153e4ad4SBenjamin Mugnier 
vgxy61_update_exposure(struct vgxy61_dev * sensor,u16 new_expo_long,enum vgxy61_hdr_mode hdr)986153e4ad4SBenjamin Mugnier static int vgxy61_update_exposure(struct vgxy61_dev *sensor, u16 new_expo_long,
987153e4ad4SBenjamin Mugnier 				  enum vgxy61_hdr_mode hdr)
988153e4ad4SBenjamin Mugnier {
989153e4ad4SBenjamin Mugnier 	struct i2c_client *client = sensor->i2c_client;
990153e4ad4SBenjamin Mugnier 	u16 new_expo_short = 0;
991153e4ad4SBenjamin Mugnier 	u16 expo_short_max = 0;
992153e4ad4SBenjamin Mugnier 	u16 expo_long_min = VGXY61_MIN_EXPOSURE;
993483af3feSBenjamin Mugnier 	u16 expo_long_max = 0;
994153e4ad4SBenjamin Mugnier 
995153e4ad4SBenjamin Mugnier 	/* Compute short exposure according to hdr mode and long exposure */
996153e4ad4SBenjamin Mugnier 	switch (hdr) {
997153e4ad4SBenjamin Mugnier 	case VGXY61_HDR_LINEAR:
998153e4ad4SBenjamin Mugnier 		/*
999153e4ad4SBenjamin Mugnier 		 * Take ratio into account for minimal exposures in
1000153e4ad4SBenjamin Mugnier 		 * VGXY61_HDR_LINEAR
1001153e4ad4SBenjamin Mugnier 		 */
1002153e4ad4SBenjamin Mugnier 		expo_long_min = VGXY61_MIN_EXPOSURE * VGXY61_HDR_LINEAR_RATIO;
1003153e4ad4SBenjamin Mugnier 		new_expo_long = max(expo_long_min, new_expo_long);
1004153e4ad4SBenjamin Mugnier 
1005153e4ad4SBenjamin Mugnier 		expo_long_max =
1006153e4ad4SBenjamin Mugnier 			vgxy61_get_expo_long_max(sensor,
1007153e4ad4SBenjamin Mugnier 						 VGXY61_HDR_LINEAR_RATIO);
1008153e4ad4SBenjamin Mugnier 		expo_short_max = (expo_long_max +
1009153e4ad4SBenjamin Mugnier 				 (VGXY61_HDR_LINEAR_RATIO / 2)) /
1010153e4ad4SBenjamin Mugnier 				 VGXY61_HDR_LINEAR_RATIO;
1011153e4ad4SBenjamin Mugnier 		new_expo_short = (new_expo_long +
1012153e4ad4SBenjamin Mugnier 				 (VGXY61_HDR_LINEAR_RATIO / 2)) /
1013153e4ad4SBenjamin Mugnier 				 VGXY61_HDR_LINEAR_RATIO;
1014153e4ad4SBenjamin Mugnier 		break;
1015153e4ad4SBenjamin Mugnier 	case VGXY61_HDR_SUB:
1016153e4ad4SBenjamin Mugnier 		new_expo_long = max(expo_long_min, new_expo_long);
1017153e4ad4SBenjamin Mugnier 
1018153e4ad4SBenjamin Mugnier 		expo_long_max = vgxy61_get_expo_long_max(sensor, 1);
1019153e4ad4SBenjamin Mugnier 		/* Short and long are the same in VGXY61_HDR_SUB */
1020153e4ad4SBenjamin Mugnier 		expo_short_max = expo_long_max;
1021153e4ad4SBenjamin Mugnier 		new_expo_short = new_expo_long;
1022153e4ad4SBenjamin Mugnier 		break;
1023153e4ad4SBenjamin Mugnier 	case VGXY61_NO_HDR:
1024153e4ad4SBenjamin Mugnier 		new_expo_long = max(expo_long_min, new_expo_long);
1025153e4ad4SBenjamin Mugnier 
1026153e4ad4SBenjamin Mugnier 		/*
1027153e4ad4SBenjamin Mugnier 		 * As short expo is 0 here, only the second rule of thumb
1028153e4ad4SBenjamin Mugnier 		 * applies, see vgxy61_get_expo_long_max for more
1029153e4ad4SBenjamin Mugnier 		 */
1030153e4ad4SBenjamin Mugnier 		expo_long_max = sensor->frame_length - VGXY61_EXPOS_ROT_TERM;
1031153e4ad4SBenjamin Mugnier 		break;
1032153e4ad4SBenjamin Mugnier 	default:
1033153e4ad4SBenjamin Mugnier 		/* Should never happen */
1034153e4ad4SBenjamin Mugnier 		WARN_ON(true);
1035153e4ad4SBenjamin Mugnier 		break;
1036153e4ad4SBenjamin Mugnier 	}
1037153e4ad4SBenjamin Mugnier 
1038153e4ad4SBenjamin Mugnier 	/* If this happens, something is wrong with formulas */
1039153e4ad4SBenjamin Mugnier 	WARN_ON(expo_long_min > expo_long_max);
1040153e4ad4SBenjamin Mugnier 
1041153e4ad4SBenjamin Mugnier 	if (new_expo_long > expo_long_max) {
1042153e4ad4SBenjamin Mugnier 		dev_warn(&client->dev, "Exposure %d too high, clamping to %d\n",
1043153e4ad4SBenjamin Mugnier 			 new_expo_long, expo_long_max);
1044153e4ad4SBenjamin Mugnier 		new_expo_long = expo_long_max;
1045153e4ad4SBenjamin Mugnier 		new_expo_short = expo_short_max;
1046153e4ad4SBenjamin Mugnier 	}
1047153e4ad4SBenjamin Mugnier 
1048153e4ad4SBenjamin Mugnier 	sensor->expo_long = new_expo_long;
1049153e4ad4SBenjamin Mugnier 	sensor->expo_short = new_expo_short;
1050153e4ad4SBenjamin Mugnier 	sensor->expo_max = expo_long_max;
1051153e4ad4SBenjamin Mugnier 	sensor->expo_min = expo_long_min;
1052153e4ad4SBenjamin Mugnier 
1053153e4ad4SBenjamin Mugnier 	if (sensor->streaming)
1054153e4ad4SBenjamin Mugnier 		return vgxy61_apply_exposure(sensor);
1055153e4ad4SBenjamin Mugnier 	return 0;
1056153e4ad4SBenjamin Mugnier }
1057153e4ad4SBenjamin Mugnier 
vgxy61_apply_framelength(struct vgxy61_dev * sensor)1058153e4ad4SBenjamin Mugnier static int vgxy61_apply_framelength(struct vgxy61_dev *sensor)
1059153e4ad4SBenjamin Mugnier {
1060153e4ad4SBenjamin Mugnier 	return vgxy61_write_reg(sensor, VGXY61_REG_FRAME_LENGTH,
1061153e4ad4SBenjamin Mugnier 				sensor->frame_length, NULL);
1062153e4ad4SBenjamin Mugnier }
1063153e4ad4SBenjamin Mugnier 
vgxy61_update_vblank(struct vgxy61_dev * sensor,u16 vblank,enum vgxy61_hdr_mode hdr)1064153e4ad4SBenjamin Mugnier static int vgxy61_update_vblank(struct vgxy61_dev *sensor, u16 vblank,
1065153e4ad4SBenjamin Mugnier 				enum vgxy61_hdr_mode hdr)
1066153e4ad4SBenjamin Mugnier {
1067153e4ad4SBenjamin Mugnier 	int ret;
1068153e4ad4SBenjamin Mugnier 
1069153e4ad4SBenjamin Mugnier 	sensor->vblank_min = vgxy61_get_vblank_min(sensor, hdr);
1070153e4ad4SBenjamin Mugnier 	sensor->vblank = max(sensor->vblank_min, vblank);
1071153e4ad4SBenjamin Mugnier 	sensor->frame_length = sensor->current_mode->crop.height +
1072153e4ad4SBenjamin Mugnier 			       sensor->vblank;
1073153e4ad4SBenjamin Mugnier 
1074153e4ad4SBenjamin Mugnier 	/* Update exposure according to vblank */
1075153e4ad4SBenjamin Mugnier 	ret = vgxy61_update_exposure(sensor, sensor->expo_long, hdr);
1076153e4ad4SBenjamin Mugnier 	if (ret)
1077153e4ad4SBenjamin Mugnier 		return ret;
1078153e4ad4SBenjamin Mugnier 
1079153e4ad4SBenjamin Mugnier 	if (sensor->streaming)
1080153e4ad4SBenjamin Mugnier 		return vgxy61_apply_framelength(sensor);
1081153e4ad4SBenjamin Mugnier 	return 0;
1082153e4ad4SBenjamin Mugnier }
1083153e4ad4SBenjamin Mugnier 
vgxy61_apply_hdr(struct vgxy61_dev * sensor,enum vgxy61_hdr_mode index)1084153e4ad4SBenjamin Mugnier static int vgxy61_apply_hdr(struct vgxy61_dev *sensor,
1085153e4ad4SBenjamin Mugnier 			    enum vgxy61_hdr_mode index)
1086153e4ad4SBenjamin Mugnier {
1087153e4ad4SBenjamin Mugnier 	static const u8 index2val[] = {0x1, 0x4, 0xa};
1088153e4ad4SBenjamin Mugnier 
1089153e4ad4SBenjamin Mugnier 	return vgxy61_write_reg(sensor, VGXY61_REG_HDR_CTRL, index2val[index],
1090153e4ad4SBenjamin Mugnier 				NULL);
1091153e4ad4SBenjamin Mugnier }
1092153e4ad4SBenjamin Mugnier 
vgxy61_update_hdr(struct vgxy61_dev * sensor,enum vgxy61_hdr_mode index)1093153e4ad4SBenjamin Mugnier static int vgxy61_update_hdr(struct vgxy61_dev *sensor,
1094153e4ad4SBenjamin Mugnier 			     enum vgxy61_hdr_mode index)
1095153e4ad4SBenjamin Mugnier {
1096153e4ad4SBenjamin Mugnier 	int ret;
1097153e4ad4SBenjamin Mugnier 
1098153e4ad4SBenjamin Mugnier 	/*
1099153e4ad4SBenjamin Mugnier 	 * vblank and short exposure change according to HDR mode, do it first
1100153e4ad4SBenjamin Mugnier 	 * as it can violate sensors 'rule of thumbs' and therefore will require
1101153e4ad4SBenjamin Mugnier 	 * to change the long exposure.
1102153e4ad4SBenjamin Mugnier 	 */
1103153e4ad4SBenjamin Mugnier 	ret = vgxy61_update_vblank(sensor, sensor->vblank, index);
1104153e4ad4SBenjamin Mugnier 	if (ret)
1105153e4ad4SBenjamin Mugnier 		return ret;
1106153e4ad4SBenjamin Mugnier 
1107153e4ad4SBenjamin Mugnier 	/* Update strobe mode according to HDR */
1108153e4ad4SBenjamin Mugnier 	ret = vgxy61_update_gpios_strobe_mode(sensor, index);
1109153e4ad4SBenjamin Mugnier 	if (ret)
1110153e4ad4SBenjamin Mugnier 		return ret;
1111153e4ad4SBenjamin Mugnier 
1112153e4ad4SBenjamin Mugnier 	sensor->hdr = index;
1113153e4ad4SBenjamin Mugnier 
1114153e4ad4SBenjamin Mugnier 	if (sensor->streaming)
1115153e4ad4SBenjamin Mugnier 		return vgxy61_apply_hdr(sensor, sensor->hdr);
1116153e4ad4SBenjamin Mugnier 	return 0;
1117153e4ad4SBenjamin Mugnier }
1118153e4ad4SBenjamin Mugnier 
vgxy61_apply_settings(struct vgxy61_dev * sensor)1119153e4ad4SBenjamin Mugnier static int vgxy61_apply_settings(struct vgxy61_dev *sensor)
1120153e4ad4SBenjamin Mugnier {
1121153e4ad4SBenjamin Mugnier 	int ret;
1122153e4ad4SBenjamin Mugnier 	unsigned int i;
1123153e4ad4SBenjamin Mugnier 
1124153e4ad4SBenjamin Mugnier 	ret = vgxy61_apply_hdr(sensor, sensor->hdr);
1125153e4ad4SBenjamin Mugnier 	if (ret)
1126153e4ad4SBenjamin Mugnier 		return ret;
1127153e4ad4SBenjamin Mugnier 
1128153e4ad4SBenjamin Mugnier 	ret = vgxy61_apply_framelength(sensor);
1129153e4ad4SBenjamin Mugnier 	if (ret)
1130153e4ad4SBenjamin Mugnier 		return ret;
1131153e4ad4SBenjamin Mugnier 
1132153e4ad4SBenjamin Mugnier 	ret = vgxy61_apply_exposure(sensor);
1133153e4ad4SBenjamin Mugnier 	if (ret)
1134153e4ad4SBenjamin Mugnier 		return ret;
1135153e4ad4SBenjamin Mugnier 
1136153e4ad4SBenjamin Mugnier 	ret = vgxy61_write_reg(sensor, VGXY61_REG_ANALOG_GAIN,
1137153e4ad4SBenjamin Mugnier 			       sensor->analog_gain, NULL);
1138153e4ad4SBenjamin Mugnier 	if (ret)
1139153e4ad4SBenjamin Mugnier 		return ret;
1140153e4ad4SBenjamin Mugnier 	ret = vgxy61_apply_digital_gain(sensor, sensor->digital_gain);
1141153e4ad4SBenjamin Mugnier 	if (ret)
1142153e4ad4SBenjamin Mugnier 		return ret;
1143153e4ad4SBenjamin Mugnier 
1144153e4ad4SBenjamin Mugnier 	ret = vgxy61_write_reg(sensor, VGXY61_REG_ORIENTATION,
1145153e4ad4SBenjamin Mugnier 			       sensor->hflip | (sensor->vflip << 1), NULL);
1146153e4ad4SBenjamin Mugnier 	if (ret)
1147153e4ad4SBenjamin Mugnier 		return ret;
1148153e4ad4SBenjamin Mugnier 
1149153e4ad4SBenjamin Mugnier 	ret = vgxy61_apply_patgen(sensor, sensor->pattern);
1150153e4ad4SBenjamin Mugnier 	if (ret)
1151153e4ad4SBenjamin Mugnier 		return ret;
1152153e4ad4SBenjamin Mugnier 
1153153e4ad4SBenjamin Mugnier 	for (i = 0; i < VGXY61_NB_GPIOS; i++) {
1154153e4ad4SBenjamin Mugnier 		ret = vgxy61_apply_gpiox_strobe_mode(sensor,
1155153e4ad4SBenjamin Mugnier 						     sensor->strobe_mode, i);
1156153e4ad4SBenjamin Mugnier 		if (ret)
1157153e4ad4SBenjamin Mugnier 			return ret;
1158153e4ad4SBenjamin Mugnier 	}
1159153e4ad4SBenjamin Mugnier 
1160153e4ad4SBenjamin Mugnier 	return 0;
1161153e4ad4SBenjamin Mugnier }
1162153e4ad4SBenjamin Mugnier 
vgxy61_stream_enable(struct vgxy61_dev * sensor)1163153e4ad4SBenjamin Mugnier static int vgxy61_stream_enable(struct vgxy61_dev *sensor)
1164153e4ad4SBenjamin Mugnier {
1165153e4ad4SBenjamin Mugnier 	struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd);
1166153e4ad4SBenjamin Mugnier 	const struct v4l2_rect *crop = &sensor->current_mode->crop;
1167153e4ad4SBenjamin Mugnier 	int ret = 0;
1168153e4ad4SBenjamin Mugnier 
1169153e4ad4SBenjamin Mugnier 	ret = vgxy61_check_bw(sensor);
1170153e4ad4SBenjamin Mugnier 	if (ret)
1171153e4ad4SBenjamin Mugnier 		return ret;
1172153e4ad4SBenjamin Mugnier 
1173153e4ad4SBenjamin Mugnier 	ret = pm_runtime_get_sync(&client->dev);
1174153e4ad4SBenjamin Mugnier 	if (ret < 0) {
1175153e4ad4SBenjamin Mugnier 		pm_runtime_put_autosuspend(&client->dev);
1176153e4ad4SBenjamin Mugnier 		return ret;
1177153e4ad4SBenjamin Mugnier 	}
1178153e4ad4SBenjamin Mugnier 
1179483af3feSBenjamin Mugnier 	/* pm_runtime_get_sync() can return 1 as a valid return code */
1180483af3feSBenjamin Mugnier 	ret = 0;
1181483af3feSBenjamin Mugnier 
1182153e4ad4SBenjamin Mugnier 	vgxy61_write_reg(sensor, VGXY61_REG_FORMAT_CTRL,
1183153e4ad4SBenjamin Mugnier 			 get_bpp_by_code(sensor->fmt.code), &ret);
1184153e4ad4SBenjamin Mugnier 	vgxy61_write_reg(sensor, VGXY61_REG_OIF_ROI0_CTRL,
1185153e4ad4SBenjamin Mugnier 			 get_data_type_by_code(sensor->fmt.code), &ret);
1186153e4ad4SBenjamin Mugnier 
1187153e4ad4SBenjamin Mugnier 	vgxy61_write_reg(sensor, VGXY61_REG_READOUT_CTRL,
1188153e4ad4SBenjamin Mugnier 			 sensor->current_mode->bin_mode, &ret);
1189153e4ad4SBenjamin Mugnier 	vgxy61_write_reg(sensor, VGXY61_REG_ROI0_START_H, crop->left, &ret);
1190153e4ad4SBenjamin Mugnier 	vgxy61_write_reg(sensor, VGXY61_REG_ROI0_END_H,
1191153e4ad4SBenjamin Mugnier 			 crop->left + crop->width - 1, &ret);
1192153e4ad4SBenjamin Mugnier 	vgxy61_write_reg(sensor, VGXY61_REG_ROI0_START_V, crop->top, &ret);
1193153e4ad4SBenjamin Mugnier 	vgxy61_write_reg(sensor, VGXY61_REG_ROI0_END_V,
1194153e4ad4SBenjamin Mugnier 			 crop->top + crop->height - 1, &ret);
1195153e4ad4SBenjamin Mugnier 	if (ret)
1196153e4ad4SBenjamin Mugnier 		goto err_rpm_put;
1197153e4ad4SBenjamin Mugnier 
1198153e4ad4SBenjamin Mugnier 	ret = vgxy61_apply_settings(sensor);
1199153e4ad4SBenjamin Mugnier 	if (ret)
1200153e4ad4SBenjamin Mugnier 		goto err_rpm_put;
1201153e4ad4SBenjamin Mugnier 
1202153e4ad4SBenjamin Mugnier 	ret = vgxy61_write_reg(sensor, VGXY61_REG_STREAMING,
1203153e4ad4SBenjamin Mugnier 			       VGXY61_STREAMING_REQ_START, NULL);
1204153e4ad4SBenjamin Mugnier 	if (ret)
1205153e4ad4SBenjamin Mugnier 		goto err_rpm_put;
1206153e4ad4SBenjamin Mugnier 
1207153e4ad4SBenjamin Mugnier 	ret = vgxy61_poll_reg(sensor, VGXY61_REG_STREAMING,
1208153e4ad4SBenjamin Mugnier 			      VGXY61_STREAMING_NO_REQ, VGXY61_TIMEOUT_MS);
1209153e4ad4SBenjamin Mugnier 	if (ret)
1210153e4ad4SBenjamin Mugnier 		goto err_rpm_put;
1211153e4ad4SBenjamin Mugnier 
1212153e4ad4SBenjamin Mugnier 	ret = vgxy61_wait_state(sensor, VGXY61_SYSTEM_FSM_STREAMING,
1213153e4ad4SBenjamin Mugnier 				VGXY61_TIMEOUT_MS);
1214153e4ad4SBenjamin Mugnier 	if (ret)
1215153e4ad4SBenjamin Mugnier 		goto err_rpm_put;
1216153e4ad4SBenjamin Mugnier 
1217153e4ad4SBenjamin Mugnier 	/* vflip and hflip cannot change during streaming */
1218153e4ad4SBenjamin Mugnier 	__v4l2_ctrl_grab(sensor->vflip_ctrl, true);
1219153e4ad4SBenjamin Mugnier 	__v4l2_ctrl_grab(sensor->hflip_ctrl, true);
1220153e4ad4SBenjamin Mugnier 
1221153e4ad4SBenjamin Mugnier 	return 0;
1222153e4ad4SBenjamin Mugnier 
1223153e4ad4SBenjamin Mugnier err_rpm_put:
1224153e4ad4SBenjamin Mugnier 	pm_runtime_put(&client->dev);
1225153e4ad4SBenjamin Mugnier 	return ret;
1226153e4ad4SBenjamin Mugnier }
1227153e4ad4SBenjamin Mugnier 
vgxy61_stream_disable(struct vgxy61_dev * sensor)1228153e4ad4SBenjamin Mugnier static int vgxy61_stream_disable(struct vgxy61_dev *sensor)
1229153e4ad4SBenjamin Mugnier {
1230153e4ad4SBenjamin Mugnier 	struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd);
1231153e4ad4SBenjamin Mugnier 	int ret;
1232153e4ad4SBenjamin Mugnier 
1233153e4ad4SBenjamin Mugnier 	ret = vgxy61_write_reg(sensor, VGXY61_REG_STREAMING,
1234153e4ad4SBenjamin Mugnier 			       VGXY61_STREAMING_REQ_STOP, NULL);
1235153e4ad4SBenjamin Mugnier 	if (ret)
1236153e4ad4SBenjamin Mugnier 		goto err_str_dis;
1237153e4ad4SBenjamin Mugnier 
1238153e4ad4SBenjamin Mugnier 	ret = vgxy61_poll_reg(sensor, VGXY61_REG_STREAMING,
1239153e4ad4SBenjamin Mugnier 			      VGXY61_STREAMING_NO_REQ, 2000);
1240153e4ad4SBenjamin Mugnier 	if (ret)
1241153e4ad4SBenjamin Mugnier 		goto err_str_dis;
1242153e4ad4SBenjamin Mugnier 
1243153e4ad4SBenjamin Mugnier 	ret = vgxy61_wait_state(sensor, VGXY61_SYSTEM_FSM_SW_STBY,
1244153e4ad4SBenjamin Mugnier 				VGXY61_TIMEOUT_MS);
1245153e4ad4SBenjamin Mugnier 	if (ret)
1246153e4ad4SBenjamin Mugnier 		goto err_str_dis;
1247153e4ad4SBenjamin Mugnier 
1248153e4ad4SBenjamin Mugnier 	__v4l2_ctrl_grab(sensor->vflip_ctrl, false);
1249153e4ad4SBenjamin Mugnier 	__v4l2_ctrl_grab(sensor->hflip_ctrl, false);
1250153e4ad4SBenjamin Mugnier 
1251153e4ad4SBenjamin Mugnier err_str_dis:
1252153e4ad4SBenjamin Mugnier 	if (ret)
1253153e4ad4SBenjamin Mugnier 		WARN(1, "Can't disable stream");
1254153e4ad4SBenjamin Mugnier 	pm_runtime_put(&client->dev);
1255153e4ad4SBenjamin Mugnier 
1256153e4ad4SBenjamin Mugnier 	return ret;
1257153e4ad4SBenjamin Mugnier }
1258153e4ad4SBenjamin Mugnier 
vgxy61_s_stream(struct v4l2_subdev * sd,int enable)1259153e4ad4SBenjamin Mugnier static int vgxy61_s_stream(struct v4l2_subdev *sd, int enable)
1260153e4ad4SBenjamin Mugnier {
1261153e4ad4SBenjamin Mugnier 	struct vgxy61_dev *sensor = to_vgxy61_dev(sd);
1262153e4ad4SBenjamin Mugnier 	int ret = 0;
1263153e4ad4SBenjamin Mugnier 
1264153e4ad4SBenjamin Mugnier 	mutex_lock(&sensor->lock);
1265153e4ad4SBenjamin Mugnier 
1266153e4ad4SBenjamin Mugnier 	ret = enable ? vgxy61_stream_enable(sensor) :
1267153e4ad4SBenjamin Mugnier 	      vgxy61_stream_disable(sensor);
1268153e4ad4SBenjamin Mugnier 	if (!ret)
1269153e4ad4SBenjamin Mugnier 		sensor->streaming = enable;
1270153e4ad4SBenjamin Mugnier 
1271153e4ad4SBenjamin Mugnier 	mutex_unlock(&sensor->lock);
1272153e4ad4SBenjamin Mugnier 
1273153e4ad4SBenjamin Mugnier 	return ret;
1274153e4ad4SBenjamin Mugnier }
1275153e4ad4SBenjamin Mugnier 
vgxy61_set_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * format)1276153e4ad4SBenjamin Mugnier static int vgxy61_set_fmt(struct v4l2_subdev *sd,
1277153e4ad4SBenjamin Mugnier 			  struct v4l2_subdev_state *sd_state,
1278153e4ad4SBenjamin Mugnier 			  struct v4l2_subdev_format *format)
1279153e4ad4SBenjamin Mugnier {
1280153e4ad4SBenjamin Mugnier 	struct vgxy61_dev *sensor = to_vgxy61_dev(sd);
1281153e4ad4SBenjamin Mugnier 	const struct vgxy61_mode_info *new_mode;
1282153e4ad4SBenjamin Mugnier 	struct v4l2_mbus_framefmt *fmt;
1283153e4ad4SBenjamin Mugnier 	int ret;
1284153e4ad4SBenjamin Mugnier 
1285153e4ad4SBenjamin Mugnier 	mutex_lock(&sensor->lock);
1286153e4ad4SBenjamin Mugnier 
1287153e4ad4SBenjamin Mugnier 	if (sensor->streaming) {
1288153e4ad4SBenjamin Mugnier 		ret = -EBUSY;
1289153e4ad4SBenjamin Mugnier 		goto out;
1290153e4ad4SBenjamin Mugnier 	}
1291153e4ad4SBenjamin Mugnier 
1292153e4ad4SBenjamin Mugnier 	ret = vgxy61_try_fmt_internal(sd, &format->format, &new_mode);
1293153e4ad4SBenjamin Mugnier 	if (ret)
1294153e4ad4SBenjamin Mugnier 		goto out;
1295153e4ad4SBenjamin Mugnier 
1296153e4ad4SBenjamin Mugnier 	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
1297153e4ad4SBenjamin Mugnier 		fmt = v4l2_subdev_get_try_format(sd, sd_state, 0);
1298153e4ad4SBenjamin Mugnier 		*fmt = format->format;
1299153e4ad4SBenjamin Mugnier 	} else if (sensor->current_mode != new_mode ||
1300153e4ad4SBenjamin Mugnier 		   sensor->fmt.code != format->format.code) {
1301153e4ad4SBenjamin Mugnier 		fmt = &sensor->fmt;
1302153e4ad4SBenjamin Mugnier 		*fmt = format->format;
1303153e4ad4SBenjamin Mugnier 
1304153e4ad4SBenjamin Mugnier 		sensor->current_mode = new_mode;
1305153e4ad4SBenjamin Mugnier 
1306153e4ad4SBenjamin Mugnier 		/* Reset vblank and framelength to default */
1307153e4ad4SBenjamin Mugnier 		ret = vgxy61_update_vblank(sensor,
1308153e4ad4SBenjamin Mugnier 					   VGXY61_FRAME_LENGTH_DEF -
1309153e4ad4SBenjamin Mugnier 					   new_mode->crop.height,
1310153e4ad4SBenjamin Mugnier 					   sensor->hdr);
1311153e4ad4SBenjamin Mugnier 
1312153e4ad4SBenjamin Mugnier 		/* Update controls to reflect new mode */
1313153e4ad4SBenjamin Mugnier 		__v4l2_ctrl_s_ctrl_int64(sensor->pixel_rate_ctrl,
1314153e4ad4SBenjamin Mugnier 					 get_pixel_rate(sensor));
1315153e4ad4SBenjamin Mugnier 		__v4l2_ctrl_modify_range(sensor->vblank_ctrl,
1316153e4ad4SBenjamin Mugnier 					 sensor->vblank_min,
1317153e4ad4SBenjamin Mugnier 					 0xffff - new_mode->crop.height,
1318153e4ad4SBenjamin Mugnier 					 1, sensor->vblank);
1319153e4ad4SBenjamin Mugnier 		__v4l2_ctrl_s_ctrl(sensor->vblank_ctrl, sensor->vblank);
1320153e4ad4SBenjamin Mugnier 		__v4l2_ctrl_modify_range(sensor->expo_ctrl, sensor->expo_min,
1321153e4ad4SBenjamin Mugnier 					 sensor->expo_max, 1,
1322153e4ad4SBenjamin Mugnier 					 sensor->expo_long);
1323153e4ad4SBenjamin Mugnier 	}
1324153e4ad4SBenjamin Mugnier 
1325153e4ad4SBenjamin Mugnier out:
1326153e4ad4SBenjamin Mugnier 	mutex_unlock(&sensor->lock);
1327153e4ad4SBenjamin Mugnier 
1328153e4ad4SBenjamin Mugnier 	return ret;
1329153e4ad4SBenjamin Mugnier }
1330153e4ad4SBenjamin Mugnier 
vgxy61_init_cfg(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state)1331153e4ad4SBenjamin Mugnier static int vgxy61_init_cfg(struct v4l2_subdev *sd,
1332153e4ad4SBenjamin Mugnier 			   struct v4l2_subdev_state *sd_state)
1333153e4ad4SBenjamin Mugnier {
1334153e4ad4SBenjamin Mugnier 	struct vgxy61_dev *sensor = to_vgxy61_dev(sd);
1335153e4ad4SBenjamin Mugnier 	struct v4l2_subdev_format fmt = { 0 };
1336153e4ad4SBenjamin Mugnier 
1337153e4ad4SBenjamin Mugnier 	vgxy61_fill_framefmt(sensor, sensor->current_mode, &fmt.format,
1338153e4ad4SBenjamin Mugnier 			     VGXY61_MEDIA_BUS_FMT_DEF);
1339153e4ad4SBenjamin Mugnier 
1340153e4ad4SBenjamin Mugnier 	return vgxy61_set_fmt(sd, sd_state, &fmt);
1341153e4ad4SBenjamin Mugnier }
1342153e4ad4SBenjamin Mugnier 
vgxy61_s_ctrl(struct v4l2_ctrl * ctrl)1343153e4ad4SBenjamin Mugnier static int vgxy61_s_ctrl(struct v4l2_ctrl *ctrl)
1344153e4ad4SBenjamin Mugnier {
1345153e4ad4SBenjamin Mugnier 	struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
1346153e4ad4SBenjamin Mugnier 	struct vgxy61_dev *sensor = to_vgxy61_dev(sd);
1347153e4ad4SBenjamin Mugnier 	const struct vgxy61_mode_info *cur_mode = sensor->current_mode;
1348153e4ad4SBenjamin Mugnier 	int ret;
1349153e4ad4SBenjamin Mugnier 
1350153e4ad4SBenjamin Mugnier 	switch (ctrl->id) {
1351153e4ad4SBenjamin Mugnier 	case V4L2_CID_EXPOSURE:
1352153e4ad4SBenjamin Mugnier 		ret = vgxy61_update_exposure(sensor, ctrl->val, sensor->hdr);
1353153e4ad4SBenjamin Mugnier 		ctrl->val = sensor->expo_long;
1354153e4ad4SBenjamin Mugnier 		break;
1355153e4ad4SBenjamin Mugnier 	case V4L2_CID_ANALOGUE_GAIN:
1356153e4ad4SBenjamin Mugnier 		ret = vgxy61_update_analog_gain(sensor, ctrl->val);
1357153e4ad4SBenjamin Mugnier 		break;
1358153e4ad4SBenjamin Mugnier 	case V4L2_CID_DIGITAL_GAIN:
1359153e4ad4SBenjamin Mugnier 		ret = vgxy61_update_digital_gain(sensor, ctrl->val);
1360153e4ad4SBenjamin Mugnier 		break;
1361153e4ad4SBenjamin Mugnier 	case V4L2_CID_VFLIP:
1362153e4ad4SBenjamin Mugnier 	case V4L2_CID_HFLIP:
1363153e4ad4SBenjamin Mugnier 		if (sensor->streaming) {
1364153e4ad4SBenjamin Mugnier 			ret = -EBUSY;
1365153e4ad4SBenjamin Mugnier 			break;
1366153e4ad4SBenjamin Mugnier 		}
1367153e4ad4SBenjamin Mugnier 		if (ctrl->id == V4L2_CID_VFLIP)
1368153e4ad4SBenjamin Mugnier 			sensor->vflip = ctrl->val;
1369153e4ad4SBenjamin Mugnier 		if (ctrl->id == V4L2_CID_HFLIP)
1370153e4ad4SBenjamin Mugnier 			sensor->hflip = ctrl->val;
1371153e4ad4SBenjamin Mugnier 		ret = 0;
1372153e4ad4SBenjamin Mugnier 		break;
1373153e4ad4SBenjamin Mugnier 	case V4L2_CID_TEST_PATTERN:
1374153e4ad4SBenjamin Mugnier 		ret = vgxy61_update_patgen(sensor, ctrl->val);
1375153e4ad4SBenjamin Mugnier 		break;
1376153e4ad4SBenjamin Mugnier 	case V4L2_CID_HDR_SENSOR_MODE:
1377153e4ad4SBenjamin Mugnier 		ret = vgxy61_update_hdr(sensor, ctrl->val);
1378153e4ad4SBenjamin Mugnier 		/* Update vblank and exposure controls to match new hdr */
1379153e4ad4SBenjamin Mugnier 		__v4l2_ctrl_modify_range(sensor->vblank_ctrl,
1380153e4ad4SBenjamin Mugnier 					 sensor->vblank_min,
1381153e4ad4SBenjamin Mugnier 					 0xffff - cur_mode->crop.height,
1382153e4ad4SBenjamin Mugnier 					 1, sensor->vblank);
1383153e4ad4SBenjamin Mugnier 		__v4l2_ctrl_modify_range(sensor->expo_ctrl, sensor->expo_min,
1384153e4ad4SBenjamin Mugnier 					 sensor->expo_max, 1,
1385153e4ad4SBenjamin Mugnier 					 sensor->expo_long);
1386153e4ad4SBenjamin Mugnier 		break;
1387153e4ad4SBenjamin Mugnier 	case V4L2_CID_VBLANK:
1388153e4ad4SBenjamin Mugnier 		ret = vgxy61_update_vblank(sensor, ctrl->val, sensor->hdr);
1389153e4ad4SBenjamin Mugnier 		/* Update exposure control to match new vblank */
1390153e4ad4SBenjamin Mugnier 		__v4l2_ctrl_modify_range(sensor->expo_ctrl, sensor->expo_min,
1391153e4ad4SBenjamin Mugnier 					 sensor->expo_max, 1,
1392153e4ad4SBenjamin Mugnier 					 sensor->expo_long);
1393153e4ad4SBenjamin Mugnier 		break;
1394153e4ad4SBenjamin Mugnier 	default:
1395153e4ad4SBenjamin Mugnier 		ret = -EINVAL;
1396153e4ad4SBenjamin Mugnier 		break;
1397153e4ad4SBenjamin Mugnier 	}
1398153e4ad4SBenjamin Mugnier 
1399153e4ad4SBenjamin Mugnier 	return ret;
1400153e4ad4SBenjamin Mugnier }
1401153e4ad4SBenjamin Mugnier 
1402153e4ad4SBenjamin Mugnier static const struct v4l2_ctrl_ops vgxy61_ctrl_ops = {
1403153e4ad4SBenjamin Mugnier 	.s_ctrl = vgxy61_s_ctrl,
1404153e4ad4SBenjamin Mugnier };
1405153e4ad4SBenjamin Mugnier 
vgxy61_init_controls(struct vgxy61_dev * sensor)1406153e4ad4SBenjamin Mugnier static int vgxy61_init_controls(struct vgxy61_dev *sensor)
1407153e4ad4SBenjamin Mugnier {
1408153e4ad4SBenjamin Mugnier 	const struct v4l2_ctrl_ops *ops = &vgxy61_ctrl_ops;
1409153e4ad4SBenjamin Mugnier 	struct v4l2_ctrl_handler *hdl = &sensor->ctrl_handler;
1410153e4ad4SBenjamin Mugnier 	const struct vgxy61_mode_info *cur_mode = sensor->current_mode;
1411153e4ad4SBenjamin Mugnier 	struct v4l2_ctrl *ctrl;
1412153e4ad4SBenjamin Mugnier 	int ret;
1413153e4ad4SBenjamin Mugnier 
1414153e4ad4SBenjamin Mugnier 	v4l2_ctrl_handler_init(hdl, 16);
1415153e4ad4SBenjamin Mugnier 	/* We can use our own mutex for the ctrl lock */
1416153e4ad4SBenjamin Mugnier 	hdl->lock = &sensor->lock;
1417153e4ad4SBenjamin Mugnier 	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_ANALOGUE_GAIN, 0, 0x1c, 1,
1418153e4ad4SBenjamin Mugnier 			  sensor->analog_gain);
1419153e4ad4SBenjamin Mugnier 	v4l2_ctrl_new_std(hdl, ops, V4L2_CID_DIGITAL_GAIN, 0, 0xfff, 1,
1420153e4ad4SBenjamin Mugnier 			  sensor->digital_gain);
1421153e4ad4SBenjamin Mugnier 	v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN,
1422153e4ad4SBenjamin Mugnier 				     ARRAY_SIZE(vgxy61_test_pattern_menu) - 1,
1423153e4ad4SBenjamin Mugnier 				     0, 0, vgxy61_test_pattern_menu);
1424153e4ad4SBenjamin Mugnier 	ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HBLANK, 0,
1425153e4ad4SBenjamin Mugnier 				 sensor->line_length, 1,
1426153e4ad4SBenjamin Mugnier 				 sensor->line_length - cur_mode->width);
1427153e4ad4SBenjamin Mugnier 	if (ctrl)
1428153e4ad4SBenjamin Mugnier 		ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
1429153e4ad4SBenjamin Mugnier 	ctrl = v4l2_ctrl_new_int_menu(hdl, ops, V4L2_CID_LINK_FREQ,
1430153e4ad4SBenjamin Mugnier 				      ARRAY_SIZE(link_freq) - 1, 0, link_freq);
1431153e4ad4SBenjamin Mugnier 	if (ctrl)
1432153e4ad4SBenjamin Mugnier 		ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
1433153e4ad4SBenjamin Mugnier 	v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_HDR_SENSOR_MODE,
1434153e4ad4SBenjamin Mugnier 				     ARRAY_SIZE(vgxy61_hdr_mode_menu) - 1, 0,
1435153e4ad4SBenjamin Mugnier 				     VGXY61_NO_HDR, vgxy61_hdr_mode_menu);
1436153e4ad4SBenjamin Mugnier 
1437153e4ad4SBenjamin Mugnier 	/*
1438153e4ad4SBenjamin Mugnier 	 * Keep a pointer to these controls as we need to update them when
1439153e4ad4SBenjamin Mugnier 	 * setting the format
1440153e4ad4SBenjamin Mugnier 	 */
1441153e4ad4SBenjamin Mugnier 	sensor->pixel_rate_ctrl = v4l2_ctrl_new_std(hdl, ops,
1442153e4ad4SBenjamin Mugnier 						    V4L2_CID_PIXEL_RATE, 1,
1443153e4ad4SBenjamin Mugnier 						    INT_MAX, 1,
1444153e4ad4SBenjamin Mugnier 						    get_pixel_rate(sensor));
1445153e4ad4SBenjamin Mugnier 	if (sensor->pixel_rate_ctrl)
1446153e4ad4SBenjamin Mugnier 		sensor->pixel_rate_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
1447153e4ad4SBenjamin Mugnier 	sensor->expo_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,
1448153e4ad4SBenjamin Mugnier 					      sensor->expo_min,
1449153e4ad4SBenjamin Mugnier 					      sensor->expo_max, 1,
1450153e4ad4SBenjamin Mugnier 					      sensor->expo_long);
1451153e4ad4SBenjamin Mugnier 	sensor->vblank_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VBLANK,
1452153e4ad4SBenjamin Mugnier 						sensor->vblank_min,
1453153e4ad4SBenjamin Mugnier 						0xffff - cur_mode->crop.height,
1454153e4ad4SBenjamin Mugnier 						1, sensor->vblank);
1455153e4ad4SBenjamin Mugnier 	sensor->vflip_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP,
1456153e4ad4SBenjamin Mugnier 					       0, 1, 1, sensor->vflip);
1457153e4ad4SBenjamin Mugnier 	sensor->hflip_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP,
1458153e4ad4SBenjamin Mugnier 					       0, 1, 1, sensor->hflip);
1459153e4ad4SBenjamin Mugnier 
1460153e4ad4SBenjamin Mugnier 	if (hdl->error) {
1461153e4ad4SBenjamin Mugnier 		ret = hdl->error;
1462153e4ad4SBenjamin Mugnier 		goto free_ctrls;
1463153e4ad4SBenjamin Mugnier 	}
1464153e4ad4SBenjamin Mugnier 
1465153e4ad4SBenjamin Mugnier 	sensor->sd.ctrl_handler = hdl;
1466153e4ad4SBenjamin Mugnier 	return 0;
1467153e4ad4SBenjamin Mugnier 
1468153e4ad4SBenjamin Mugnier free_ctrls:
1469153e4ad4SBenjamin Mugnier 	v4l2_ctrl_handler_free(hdl);
1470153e4ad4SBenjamin Mugnier 	return ret;
1471153e4ad4SBenjamin Mugnier }
1472153e4ad4SBenjamin Mugnier 
1473153e4ad4SBenjamin Mugnier static const struct v4l2_subdev_video_ops vgxy61_video_ops = {
1474153e4ad4SBenjamin Mugnier 	.s_stream = vgxy61_s_stream,
1475153e4ad4SBenjamin Mugnier };
1476153e4ad4SBenjamin Mugnier 
1477153e4ad4SBenjamin Mugnier static const struct v4l2_subdev_pad_ops vgxy61_pad_ops = {
1478153e4ad4SBenjamin Mugnier 	.init_cfg = vgxy61_init_cfg,
1479153e4ad4SBenjamin Mugnier 	.enum_mbus_code = vgxy61_enum_mbus_code,
1480153e4ad4SBenjamin Mugnier 	.get_fmt = vgxy61_get_fmt,
1481153e4ad4SBenjamin Mugnier 	.set_fmt = vgxy61_set_fmt,
1482153e4ad4SBenjamin Mugnier 	.get_selection = vgxy61_get_selection,
1483153e4ad4SBenjamin Mugnier 	.enum_frame_size = vgxy61_enum_frame_size,
1484153e4ad4SBenjamin Mugnier };
1485153e4ad4SBenjamin Mugnier 
1486153e4ad4SBenjamin Mugnier static const struct v4l2_subdev_ops vgxy61_subdev_ops = {
1487153e4ad4SBenjamin Mugnier 	.video = &vgxy61_video_ops,
1488153e4ad4SBenjamin Mugnier 	.pad = &vgxy61_pad_ops,
1489153e4ad4SBenjamin Mugnier };
1490153e4ad4SBenjamin Mugnier 
1491153e4ad4SBenjamin Mugnier static const struct media_entity_operations vgxy61_subdev_entity_ops = {
1492153e4ad4SBenjamin Mugnier 	.link_validate = v4l2_subdev_link_validate,
1493153e4ad4SBenjamin Mugnier };
1494153e4ad4SBenjamin Mugnier 
vgxy61_tx_from_ep(struct vgxy61_dev * sensor,struct fwnode_handle * handle)1495153e4ad4SBenjamin Mugnier static int vgxy61_tx_from_ep(struct vgxy61_dev *sensor,
1496153e4ad4SBenjamin Mugnier 			     struct fwnode_handle *handle)
1497153e4ad4SBenjamin Mugnier {
1498153e4ad4SBenjamin Mugnier 	struct v4l2_fwnode_endpoint ep = { .bus_type = V4L2_MBUS_CSI2_DPHY };
1499153e4ad4SBenjamin Mugnier 	struct i2c_client *client = sensor->i2c_client;
1500153e4ad4SBenjamin Mugnier 	u32 log2phy[VGXY61_NB_POLARITIES] = {~0, ~0, ~0, ~0, ~0};
1501153e4ad4SBenjamin Mugnier 	u32 phy2log[VGXY61_NB_POLARITIES] = {~0, ~0, ~0, ~0, ~0};
1502153e4ad4SBenjamin Mugnier 	int polarities[VGXY61_NB_POLARITIES] = {0, 0, 0, 0, 0};
1503153e4ad4SBenjamin Mugnier 	int l_nb;
1504153e4ad4SBenjamin Mugnier 	unsigned int p, l, i;
1505153e4ad4SBenjamin Mugnier 	int ret;
1506153e4ad4SBenjamin Mugnier 
1507153e4ad4SBenjamin Mugnier 	ret = v4l2_fwnode_endpoint_alloc_parse(handle, &ep);
1508153e4ad4SBenjamin Mugnier 	if (ret)
1509153e4ad4SBenjamin Mugnier 		return -EINVAL;
1510153e4ad4SBenjamin Mugnier 
1511153e4ad4SBenjamin Mugnier 	l_nb = ep.bus.mipi_csi2.num_data_lanes;
1512153e4ad4SBenjamin Mugnier 	if (l_nb != 1 && l_nb != 2 && l_nb != 4) {
1513153e4ad4SBenjamin Mugnier 		dev_err(&client->dev, "invalid data lane number %d\n", l_nb);
1514153e4ad4SBenjamin Mugnier 		goto error_ep;
1515153e4ad4SBenjamin Mugnier 	}
1516153e4ad4SBenjamin Mugnier 
1517153e4ad4SBenjamin Mugnier 	/* Build log2phy, phy2log and polarities from ep info */
1518153e4ad4SBenjamin Mugnier 	log2phy[0] = ep.bus.mipi_csi2.clock_lane;
1519153e4ad4SBenjamin Mugnier 	phy2log[log2phy[0]] = 0;
1520153e4ad4SBenjamin Mugnier 	for (l = 1; l < l_nb + 1; l++) {
1521153e4ad4SBenjamin Mugnier 		log2phy[l] = ep.bus.mipi_csi2.data_lanes[l - 1];
1522153e4ad4SBenjamin Mugnier 		phy2log[log2phy[l]] = l;
1523153e4ad4SBenjamin Mugnier 	}
1524153e4ad4SBenjamin Mugnier 	/*
1525153e4ad4SBenjamin Mugnier 	 * Then fill remaining slots for every physical slot to have something
1526153e4ad4SBenjamin Mugnier 	 * valid for hardware stuff.
1527153e4ad4SBenjamin Mugnier 	 */
1528153e4ad4SBenjamin Mugnier 	for (p = 0; p < VGXY61_NB_POLARITIES; p++) {
1529153e4ad4SBenjamin Mugnier 		if (phy2log[p] != ~0)
1530153e4ad4SBenjamin Mugnier 			continue;
1531153e4ad4SBenjamin Mugnier 		phy2log[p] = l;
1532153e4ad4SBenjamin Mugnier 		log2phy[l] = p;
1533153e4ad4SBenjamin Mugnier 		l++;
1534153e4ad4SBenjamin Mugnier 	}
1535153e4ad4SBenjamin Mugnier 	for (l = 0; l < l_nb + 1; l++)
1536153e4ad4SBenjamin Mugnier 		polarities[l] = ep.bus.mipi_csi2.lane_polarities[l];
1537153e4ad4SBenjamin Mugnier 
1538153e4ad4SBenjamin Mugnier 	if (log2phy[0] != 0) {
1539153e4ad4SBenjamin Mugnier 		dev_err(&client->dev, "clk lane must be map to physical lane 0\n");
1540153e4ad4SBenjamin Mugnier 		goto error_ep;
1541153e4ad4SBenjamin Mugnier 	}
1542153e4ad4SBenjamin Mugnier 	sensor->oif_ctrl = (polarities[4] << 15) + ((phy2log[4] - 1) << 13) +
1543153e4ad4SBenjamin Mugnier 			   (polarities[3] << 12) + ((phy2log[3] - 1) << 10) +
1544153e4ad4SBenjamin Mugnier 			   (polarities[2] <<  9) + ((phy2log[2] - 1) <<  7) +
1545153e4ad4SBenjamin Mugnier 			   (polarities[1] <<  6) + ((phy2log[1] - 1) <<  4) +
1546153e4ad4SBenjamin Mugnier 			   (polarities[0] <<  3) +
1547153e4ad4SBenjamin Mugnier 			   l_nb;
1548153e4ad4SBenjamin Mugnier 	sensor->nb_of_lane = l_nb;
1549153e4ad4SBenjamin Mugnier 
1550153e4ad4SBenjamin Mugnier 	dev_dbg(&client->dev, "tx uses %d lanes", l_nb);
1551c2402afcSBenjamin Mugnier 	for (i = 0; i < VGXY61_NB_POLARITIES; i++) {
1552153e4ad4SBenjamin Mugnier 		dev_dbg(&client->dev, "log2phy[%d] = %d\n", i, log2phy[i]);
1553153e4ad4SBenjamin Mugnier 		dev_dbg(&client->dev, "phy2log[%d] = %d\n", i, phy2log[i]);
1554153e4ad4SBenjamin Mugnier 		dev_dbg(&client->dev, "polarity[%d] = %d\n", i, polarities[i]);
1555153e4ad4SBenjamin Mugnier 	}
1556153e4ad4SBenjamin Mugnier 	dev_dbg(&client->dev, "oif_ctrl = 0x%04x\n", sensor->oif_ctrl);
1557153e4ad4SBenjamin Mugnier 
1558153e4ad4SBenjamin Mugnier 	v4l2_fwnode_endpoint_free(&ep);
1559153e4ad4SBenjamin Mugnier 
1560153e4ad4SBenjamin Mugnier 	return 0;
1561153e4ad4SBenjamin Mugnier 
1562153e4ad4SBenjamin Mugnier error_ep:
1563153e4ad4SBenjamin Mugnier 	v4l2_fwnode_endpoint_free(&ep);
1564153e4ad4SBenjamin Mugnier 
1565153e4ad4SBenjamin Mugnier 	return -EINVAL;
1566153e4ad4SBenjamin Mugnier }
1567153e4ad4SBenjamin Mugnier 
vgxy61_configure(struct vgxy61_dev * sensor)1568153e4ad4SBenjamin Mugnier static int vgxy61_configure(struct vgxy61_dev *sensor)
1569153e4ad4SBenjamin Mugnier {
1570153e4ad4SBenjamin Mugnier 	u32 sensor_freq;
1571153e4ad4SBenjamin Mugnier 	u8 prediv, mult;
1572483af3feSBenjamin Mugnier 	int line_length;
1573153e4ad4SBenjamin Mugnier 	int ret = 0;
1574153e4ad4SBenjamin Mugnier 
1575153e4ad4SBenjamin Mugnier 	compute_pll_parameters_by_freq(sensor->clk_freq, &prediv, &mult);
1576153e4ad4SBenjamin Mugnier 	sensor_freq = (mult * sensor->clk_freq) / prediv;
1577153e4ad4SBenjamin Mugnier 	/* Frequency to data rate is 1:1 ratio for MIPI */
1578153e4ad4SBenjamin Mugnier 	sensor->data_rate_in_mbps = sensor_freq;
1579153e4ad4SBenjamin Mugnier 	/* Video timing ISP path (pixel clock)  requires 804/5 mhz = 160 mhz */
1580153e4ad4SBenjamin Mugnier 	sensor->pclk = sensor_freq / 5;
1581153e4ad4SBenjamin Mugnier 
1582153e4ad4SBenjamin Mugnier 	line_length = vgxy61_read_reg(sensor, VGXY61_REG_LINE_LENGTH);
1583153e4ad4SBenjamin Mugnier 	if (line_length < 0)
1584153e4ad4SBenjamin Mugnier 		return line_length;
1585153e4ad4SBenjamin Mugnier 	sensor->line_length = line_length;
1586153e4ad4SBenjamin Mugnier 	vgxy61_write_reg(sensor, VGXY61_REG_EXT_CLOCK, sensor->clk_freq, &ret);
1587153e4ad4SBenjamin Mugnier 	vgxy61_write_reg(sensor, VGXY61_REG_CLK_PLL_PREDIV, prediv, &ret);
1588153e4ad4SBenjamin Mugnier 	vgxy61_write_reg(sensor, VGXY61_REG_CLK_SYS_PLL_MULT, mult, &ret);
1589153e4ad4SBenjamin Mugnier 	vgxy61_write_reg(sensor, VGXY61_REG_OIF_CTRL, sensor->oif_ctrl, &ret);
1590153e4ad4SBenjamin Mugnier 	vgxy61_write_reg(sensor, VGXY61_REG_FRAME_CONTENT_CTRL, 0, &ret);
1591153e4ad4SBenjamin Mugnier 	vgxy61_write_reg(sensor, VGXY61_REG_BYPASS_CTRL, 4, &ret);
1592153e4ad4SBenjamin Mugnier 	if (ret)
1593153e4ad4SBenjamin Mugnier 		return ret;
1594153e4ad4SBenjamin Mugnier 	vgxy61_update_gpios_strobe_polarity(sensor, sensor->gpios_polarity);
1595153e4ad4SBenjamin Mugnier 	/* Set pattern generator solid to middle value */
1596153e4ad4SBenjamin Mugnier 	vgxy61_write_reg(sensor, VGXY61_REG_PATGEN_LONG_DATA_GR, 0x800, &ret);
1597153e4ad4SBenjamin Mugnier 	vgxy61_write_reg(sensor, VGXY61_REG_PATGEN_LONG_DATA_R, 0x800, &ret);
1598153e4ad4SBenjamin Mugnier 	vgxy61_write_reg(sensor, VGXY61_REG_PATGEN_LONG_DATA_B, 0x800, &ret);
1599153e4ad4SBenjamin Mugnier 	vgxy61_write_reg(sensor, VGXY61_REG_PATGEN_LONG_DATA_GB, 0x800, &ret);
1600153e4ad4SBenjamin Mugnier 	vgxy61_write_reg(sensor, VGXY61_REG_PATGEN_SHORT_DATA_GR, 0x800, &ret);
1601153e4ad4SBenjamin Mugnier 	vgxy61_write_reg(sensor, VGXY61_REG_PATGEN_SHORT_DATA_R, 0x800, &ret);
1602153e4ad4SBenjamin Mugnier 	vgxy61_write_reg(sensor, VGXY61_REG_PATGEN_SHORT_DATA_B, 0x800, &ret);
1603153e4ad4SBenjamin Mugnier 	vgxy61_write_reg(sensor, VGXY61_REG_PATGEN_SHORT_DATA_GB, 0x800, &ret);
1604153e4ad4SBenjamin Mugnier 	if (ret)
1605153e4ad4SBenjamin Mugnier 		return ret;
1606153e4ad4SBenjamin Mugnier 
1607153e4ad4SBenjamin Mugnier 	return 0;
1608153e4ad4SBenjamin Mugnier }
1609153e4ad4SBenjamin Mugnier 
vgxy61_patch(struct vgxy61_dev * sensor)1610153e4ad4SBenjamin Mugnier static int vgxy61_patch(struct vgxy61_dev *sensor)
1611153e4ad4SBenjamin Mugnier {
1612153e4ad4SBenjamin Mugnier 	struct i2c_client *client = sensor->i2c_client;
1613483af3feSBenjamin Mugnier 	int patch, ret;
1614153e4ad4SBenjamin Mugnier 
1615153e4ad4SBenjamin Mugnier 	ret = vgxy61_write_array(sensor, VGXY61_REG_FWPATCH_START_ADDR,
1616153e4ad4SBenjamin Mugnier 				 sizeof(patch_array), patch_array);
1617153e4ad4SBenjamin Mugnier 	if (ret)
1618153e4ad4SBenjamin Mugnier 		return ret;
1619153e4ad4SBenjamin Mugnier 
1620153e4ad4SBenjamin Mugnier 	ret = vgxy61_write_reg(sensor, VGXY61_REG_STBY, 0x10, NULL);
1621153e4ad4SBenjamin Mugnier 	if (ret)
1622153e4ad4SBenjamin Mugnier 		return ret;
1623153e4ad4SBenjamin Mugnier 
1624153e4ad4SBenjamin Mugnier 	ret = vgxy61_poll_reg(sensor, VGXY61_REG_STBY, 0, VGXY61_TIMEOUT_MS);
1625153e4ad4SBenjamin Mugnier 	if (ret)
1626153e4ad4SBenjamin Mugnier 		return ret;
1627153e4ad4SBenjamin Mugnier 
1628153e4ad4SBenjamin Mugnier 	patch = vgxy61_read_reg(sensor, VGXY61_REG_FWPATCH_REVISION);
1629153e4ad4SBenjamin Mugnier 	if (patch < 0)
1630153e4ad4SBenjamin Mugnier 		return patch;
1631153e4ad4SBenjamin Mugnier 
1632153e4ad4SBenjamin Mugnier 	if (patch != (VGXY61_FWPATCH_REVISION_MAJOR << 12) +
1633153e4ad4SBenjamin Mugnier 		     (VGXY61_FWPATCH_REVISION_MINOR << 8) +
1634153e4ad4SBenjamin Mugnier 		     VGXY61_FWPATCH_REVISION_MICRO) {
1635153e4ad4SBenjamin Mugnier 		dev_err(&client->dev, "bad patch version expected %d.%d.%d got %d.%d.%d\n",
1636153e4ad4SBenjamin Mugnier 			VGXY61_FWPATCH_REVISION_MAJOR,
1637153e4ad4SBenjamin Mugnier 			VGXY61_FWPATCH_REVISION_MINOR,
1638153e4ad4SBenjamin Mugnier 			VGXY61_FWPATCH_REVISION_MICRO,
1639153e4ad4SBenjamin Mugnier 			patch >> 12, (patch >> 8) & 0x0f, patch & 0xff);
1640153e4ad4SBenjamin Mugnier 		return -ENODEV;
1641153e4ad4SBenjamin Mugnier 	}
1642153e4ad4SBenjamin Mugnier 	dev_dbg(&client->dev, "patch %d.%d.%d applied\n",
1643153e4ad4SBenjamin Mugnier 		patch >> 12, (patch >> 8) & 0x0f, patch & 0xff);
1644153e4ad4SBenjamin Mugnier 
1645153e4ad4SBenjamin Mugnier 	return 0;
1646153e4ad4SBenjamin Mugnier }
1647153e4ad4SBenjamin Mugnier 
vgxy61_detect_cut_version(struct vgxy61_dev * sensor)1648153e4ad4SBenjamin Mugnier static int vgxy61_detect_cut_version(struct vgxy61_dev *sensor)
1649153e4ad4SBenjamin Mugnier {
1650153e4ad4SBenjamin Mugnier 	struct i2c_client *client = sensor->i2c_client;
1651483af3feSBenjamin Mugnier 	int device_rev;
1652153e4ad4SBenjamin Mugnier 
1653153e4ad4SBenjamin Mugnier 	device_rev = vgxy61_read_reg(sensor, VGXY61_REG_REVISION);
1654153e4ad4SBenjamin Mugnier 	if (device_rev < 0)
1655153e4ad4SBenjamin Mugnier 		return device_rev;
1656153e4ad4SBenjamin Mugnier 
1657153e4ad4SBenjamin Mugnier 	switch (device_rev >> 8) {
1658153e4ad4SBenjamin Mugnier 	case 0xA:
1659153e4ad4SBenjamin Mugnier 		dev_dbg(&client->dev, "Cut1 detected\n");
1660153e4ad4SBenjamin Mugnier 		dev_err(&client->dev, "Cut1 not supported by this driver\n");
1661153e4ad4SBenjamin Mugnier 		return -ENODEV;
1662153e4ad4SBenjamin Mugnier 	case 0xB:
1663153e4ad4SBenjamin Mugnier 		dev_dbg(&client->dev, "Cut2 detected\n");
1664153e4ad4SBenjamin Mugnier 		return 0;
1665153e4ad4SBenjamin Mugnier 	case 0xC:
1666153e4ad4SBenjamin Mugnier 		dev_dbg(&client->dev, "Cut3 detected\n");
1667153e4ad4SBenjamin Mugnier 		return 0;
1668153e4ad4SBenjamin Mugnier 	default:
1669153e4ad4SBenjamin Mugnier 		dev_err(&client->dev, "Unable to detect cut version\n");
1670153e4ad4SBenjamin Mugnier 		return -ENODEV;
1671153e4ad4SBenjamin Mugnier 	}
1672153e4ad4SBenjamin Mugnier }
1673153e4ad4SBenjamin Mugnier 
vgxy61_detect(struct vgxy61_dev * sensor)1674153e4ad4SBenjamin Mugnier static int vgxy61_detect(struct vgxy61_dev *sensor)
1675153e4ad4SBenjamin Mugnier {
1676153e4ad4SBenjamin Mugnier 	struct i2c_client *client = sensor->i2c_client;
1677483af3feSBenjamin Mugnier 	int id = 0;
1678483af3feSBenjamin Mugnier 	int ret, st;
1679153e4ad4SBenjamin Mugnier 
1680153e4ad4SBenjamin Mugnier 	id = vgxy61_read_reg(sensor, VGXY61_REG_MODEL_ID);
1681153e4ad4SBenjamin Mugnier 	if (id < 0)
1682153e4ad4SBenjamin Mugnier 		return id;
1683153e4ad4SBenjamin Mugnier 	if (id != VG5661_MODEL_ID && id != VG5761_MODEL_ID) {
1684153e4ad4SBenjamin Mugnier 		dev_warn(&client->dev, "Unsupported sensor id %x\n", id);
1685153e4ad4SBenjamin Mugnier 		return -ENODEV;
1686153e4ad4SBenjamin Mugnier 	}
1687153e4ad4SBenjamin Mugnier 	dev_dbg(&client->dev, "detected sensor id = 0x%04x\n", id);
1688153e4ad4SBenjamin Mugnier 	sensor->id = id;
1689153e4ad4SBenjamin Mugnier 
1690153e4ad4SBenjamin Mugnier 	ret = vgxy61_wait_state(sensor, VGXY61_SYSTEM_FSM_SW_STBY,
1691153e4ad4SBenjamin Mugnier 				VGXY61_TIMEOUT_MS);
1692153e4ad4SBenjamin Mugnier 	if (ret)
1693153e4ad4SBenjamin Mugnier 		return ret;
1694153e4ad4SBenjamin Mugnier 
1695153e4ad4SBenjamin Mugnier 	st = vgxy61_read_reg(sensor, VGXY61_REG_NVM);
1696153e4ad4SBenjamin Mugnier 	if (st < 0)
1697153e4ad4SBenjamin Mugnier 		return st;
1698153e4ad4SBenjamin Mugnier 	if (st != VGXY61_NVM_OK)
1699153e4ad4SBenjamin Mugnier 		dev_warn(&client->dev, "Bad nvm state got %d\n", st);
1700153e4ad4SBenjamin Mugnier 
1701153e4ad4SBenjamin Mugnier 	ret = vgxy61_detect_cut_version(sensor);
1702153e4ad4SBenjamin Mugnier 	if (ret)
1703153e4ad4SBenjamin Mugnier 		return ret;
1704153e4ad4SBenjamin Mugnier 
1705153e4ad4SBenjamin Mugnier 	return 0;
1706153e4ad4SBenjamin Mugnier }
1707153e4ad4SBenjamin Mugnier 
1708153e4ad4SBenjamin Mugnier /* Power/clock management functions */
vgxy61_power_on(struct device * dev)1709153e4ad4SBenjamin Mugnier static int vgxy61_power_on(struct device *dev)
1710153e4ad4SBenjamin Mugnier {
1711153e4ad4SBenjamin Mugnier 	struct i2c_client *client = to_i2c_client(dev);
1712153e4ad4SBenjamin Mugnier 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
1713153e4ad4SBenjamin Mugnier 	struct vgxy61_dev *sensor = to_vgxy61_dev(sd);
1714153e4ad4SBenjamin Mugnier 	int ret;
1715153e4ad4SBenjamin Mugnier 
171674b681bdSBenjamin Mugnier 	ret = regulator_bulk_enable(ARRAY_SIZE(vgxy61_supply_name),
171774b681bdSBenjamin Mugnier 				    sensor->supplies);
171874b681bdSBenjamin Mugnier 	if (ret) {
171974b681bdSBenjamin Mugnier 		dev_err(&client->dev, "failed to enable regulators %d\n", ret);
172074b681bdSBenjamin Mugnier 		return ret;
172174b681bdSBenjamin Mugnier 	}
172274b681bdSBenjamin Mugnier 
1723153e4ad4SBenjamin Mugnier 	ret = clk_prepare_enable(sensor->xclk);
1724153e4ad4SBenjamin Mugnier 	if (ret) {
1725153e4ad4SBenjamin Mugnier 		dev_err(&client->dev, "failed to enable clock %d\n", ret);
1726153e4ad4SBenjamin Mugnier 		goto disable_bulk;
1727153e4ad4SBenjamin Mugnier 	}
1728153e4ad4SBenjamin Mugnier 
1729153e4ad4SBenjamin Mugnier 	if (sensor->reset_gpio) {
1730153e4ad4SBenjamin Mugnier 		ret = vgxy61_apply_reset(sensor);
1731153e4ad4SBenjamin Mugnier 		if (ret) {
1732153e4ad4SBenjamin Mugnier 			dev_err(&client->dev, "sensor reset failed %d\n", ret);
1733153e4ad4SBenjamin Mugnier 			goto disable_clock;
1734153e4ad4SBenjamin Mugnier 		}
1735153e4ad4SBenjamin Mugnier 	}
1736153e4ad4SBenjamin Mugnier 
1737985ed1d7SBenjamin Mugnier 	ret = vgxy61_detect(sensor);
1738985ed1d7SBenjamin Mugnier 	if (ret) {
1739985ed1d7SBenjamin Mugnier 		dev_err(&client->dev, "sensor detect failed %d\n", ret);
1740985ed1d7SBenjamin Mugnier 		goto disable_clock;
1741985ed1d7SBenjamin Mugnier 	}
1742985ed1d7SBenjamin Mugnier 
1743153e4ad4SBenjamin Mugnier 	ret = vgxy61_patch(sensor);
1744153e4ad4SBenjamin Mugnier 	if (ret) {
1745153e4ad4SBenjamin Mugnier 		dev_err(&client->dev, "sensor patch failed %d\n", ret);
1746153e4ad4SBenjamin Mugnier 		goto disable_clock;
1747153e4ad4SBenjamin Mugnier 	}
1748153e4ad4SBenjamin Mugnier 
1749153e4ad4SBenjamin Mugnier 	ret = vgxy61_configure(sensor);
1750153e4ad4SBenjamin Mugnier 	if (ret) {
1751153e4ad4SBenjamin Mugnier 		dev_err(&client->dev, "sensor configuration failed %d\n", ret);
1752153e4ad4SBenjamin Mugnier 		goto disable_clock;
1753153e4ad4SBenjamin Mugnier 	}
1754153e4ad4SBenjamin Mugnier 
1755153e4ad4SBenjamin Mugnier 	return 0;
1756153e4ad4SBenjamin Mugnier 
1757153e4ad4SBenjamin Mugnier disable_clock:
1758153e4ad4SBenjamin Mugnier 	clk_disable_unprepare(sensor->xclk);
1759153e4ad4SBenjamin Mugnier disable_bulk:
1760153e4ad4SBenjamin Mugnier 	regulator_bulk_disable(ARRAY_SIZE(vgxy61_supply_name),
1761153e4ad4SBenjamin Mugnier 			       sensor->supplies);
1762153e4ad4SBenjamin Mugnier 
1763153e4ad4SBenjamin Mugnier 	return ret;
1764153e4ad4SBenjamin Mugnier }
1765153e4ad4SBenjamin Mugnier 
vgxy61_power_off(struct device * dev)1766153e4ad4SBenjamin Mugnier static int vgxy61_power_off(struct device *dev)
1767153e4ad4SBenjamin Mugnier {
1768153e4ad4SBenjamin Mugnier 	struct i2c_client *client = to_i2c_client(dev);
1769153e4ad4SBenjamin Mugnier 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
1770153e4ad4SBenjamin Mugnier 	struct vgxy61_dev *sensor = to_vgxy61_dev(sd);
1771153e4ad4SBenjamin Mugnier 
1772153e4ad4SBenjamin Mugnier 	clk_disable_unprepare(sensor->xclk);
1773153e4ad4SBenjamin Mugnier 	regulator_bulk_disable(ARRAY_SIZE(vgxy61_supply_name),
1774153e4ad4SBenjamin Mugnier 			       sensor->supplies);
1775153e4ad4SBenjamin Mugnier 	return 0;
1776153e4ad4SBenjamin Mugnier }
1777153e4ad4SBenjamin Mugnier 
vgxy61_fill_sensor_param(struct vgxy61_dev * sensor)1778153e4ad4SBenjamin Mugnier static void vgxy61_fill_sensor_param(struct vgxy61_dev *sensor)
1779153e4ad4SBenjamin Mugnier {
1780153e4ad4SBenjamin Mugnier 	if (sensor->id == VG5761_MODEL_ID) {
1781153e4ad4SBenjamin Mugnier 		sensor->sensor_width = VGX761_WIDTH;
1782153e4ad4SBenjamin Mugnier 		sensor->sensor_height = VGX761_HEIGHT;
1783153e4ad4SBenjamin Mugnier 		sensor->sensor_modes = vgx761_mode_data;
1784153e4ad4SBenjamin Mugnier 		sensor->sensor_modes_nb = ARRAY_SIZE(vgx761_mode_data);
1785153e4ad4SBenjamin Mugnier 		sensor->default_mode = &vgx761_mode_data[VGX761_DEFAULT_MODE];
1786153e4ad4SBenjamin Mugnier 		sensor->rot_term = VGX761_SHORT_ROT_TERM;
1787153e4ad4SBenjamin Mugnier 	} else if (sensor->id == VG5661_MODEL_ID) {
1788153e4ad4SBenjamin Mugnier 		sensor->sensor_width = VGX661_WIDTH;
1789153e4ad4SBenjamin Mugnier 		sensor->sensor_height = VGX661_HEIGHT;
1790153e4ad4SBenjamin Mugnier 		sensor->sensor_modes = vgx661_mode_data;
1791153e4ad4SBenjamin Mugnier 		sensor->sensor_modes_nb = ARRAY_SIZE(vgx661_mode_data);
1792153e4ad4SBenjamin Mugnier 		sensor->default_mode = &vgx661_mode_data[VGX661_DEFAULT_MODE];
1793153e4ad4SBenjamin Mugnier 		sensor->rot_term = VGX661_SHORT_ROT_TERM;
1794153e4ad4SBenjamin Mugnier 	} else {
1795153e4ad4SBenjamin Mugnier 		/* Should never happen */
1796153e4ad4SBenjamin Mugnier 		WARN_ON(true);
1797153e4ad4SBenjamin Mugnier 	}
1798153e4ad4SBenjamin Mugnier 	sensor->current_mode = sensor->default_mode;
1799153e4ad4SBenjamin Mugnier }
1800153e4ad4SBenjamin Mugnier 
vgxy61_probe(struct i2c_client * client)1801153e4ad4SBenjamin Mugnier static int vgxy61_probe(struct i2c_client *client)
1802153e4ad4SBenjamin Mugnier {
1803153e4ad4SBenjamin Mugnier 	struct device *dev = &client->dev;
1804153e4ad4SBenjamin Mugnier 	struct fwnode_handle *handle;
1805153e4ad4SBenjamin Mugnier 	struct vgxy61_dev *sensor;
1806153e4ad4SBenjamin Mugnier 	int ret;
1807153e4ad4SBenjamin Mugnier 
1808153e4ad4SBenjamin Mugnier 	sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
1809153e4ad4SBenjamin Mugnier 	if (!sensor)
1810153e4ad4SBenjamin Mugnier 		return -ENOMEM;
1811153e4ad4SBenjamin Mugnier 
1812153e4ad4SBenjamin Mugnier 	sensor->i2c_client = client;
1813153e4ad4SBenjamin Mugnier 	sensor->streaming = false;
1814153e4ad4SBenjamin Mugnier 	sensor->hdr = VGXY61_NO_HDR;
1815153e4ad4SBenjamin Mugnier 	sensor->expo_long = 200;
1816153e4ad4SBenjamin Mugnier 	sensor->expo_short = 0;
1817153e4ad4SBenjamin Mugnier 	sensor->hflip = false;
1818153e4ad4SBenjamin Mugnier 	sensor->vflip = false;
1819153e4ad4SBenjamin Mugnier 	sensor->analog_gain = 0;
1820153e4ad4SBenjamin Mugnier 	sensor->digital_gain = 256;
1821153e4ad4SBenjamin Mugnier 
1822153e4ad4SBenjamin Mugnier 	handle = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0, 0);
1823153e4ad4SBenjamin Mugnier 	if (!handle) {
1824153e4ad4SBenjamin Mugnier 		dev_err(dev, "handle node not found\n");
1825153e4ad4SBenjamin Mugnier 		return -EINVAL;
1826153e4ad4SBenjamin Mugnier 	}
1827153e4ad4SBenjamin Mugnier 
1828153e4ad4SBenjamin Mugnier 	ret = vgxy61_tx_from_ep(sensor, handle);
1829153e4ad4SBenjamin Mugnier 	fwnode_handle_put(handle);
1830153e4ad4SBenjamin Mugnier 	if (ret) {
1831153e4ad4SBenjamin Mugnier 		dev_err(dev, "Failed to parse handle %d\n", ret);
1832153e4ad4SBenjamin Mugnier 		return ret;
1833153e4ad4SBenjamin Mugnier 	}
1834153e4ad4SBenjamin Mugnier 
1835153e4ad4SBenjamin Mugnier 	sensor->xclk = devm_clk_get(dev, NULL);
1836153e4ad4SBenjamin Mugnier 	if (IS_ERR(sensor->xclk)) {
1837153e4ad4SBenjamin Mugnier 		dev_err(dev, "failed to get xclk\n");
1838153e4ad4SBenjamin Mugnier 		return PTR_ERR(sensor->xclk);
1839153e4ad4SBenjamin Mugnier 	}
1840153e4ad4SBenjamin Mugnier 	sensor->clk_freq = clk_get_rate(sensor->xclk);
1841153e4ad4SBenjamin Mugnier 	if (sensor->clk_freq < 6 * HZ_PER_MHZ ||
1842153e4ad4SBenjamin Mugnier 	    sensor->clk_freq > 27 * HZ_PER_MHZ) {
1843153e4ad4SBenjamin Mugnier 		dev_err(dev, "Only 6Mhz-27Mhz clock range supported. provide %lu MHz\n",
1844153e4ad4SBenjamin Mugnier 			sensor->clk_freq / HZ_PER_MHZ);
1845153e4ad4SBenjamin Mugnier 		return -EINVAL;
1846153e4ad4SBenjamin Mugnier 	}
1847153e4ad4SBenjamin Mugnier 	sensor->gpios_polarity =
1848153e4ad4SBenjamin Mugnier 		device_property_read_bool(dev, "st,strobe-gpios-polarity");
1849153e4ad4SBenjamin Mugnier 
1850153e4ad4SBenjamin Mugnier 	v4l2_i2c_subdev_init(&sensor->sd, client, &vgxy61_subdev_ops);
1851153e4ad4SBenjamin Mugnier 	sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1852153e4ad4SBenjamin Mugnier 	sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
1853153e4ad4SBenjamin Mugnier 	sensor->sd.entity.ops = &vgxy61_subdev_entity_ops;
1854153e4ad4SBenjamin Mugnier 	sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
1855153e4ad4SBenjamin Mugnier 
1856153e4ad4SBenjamin Mugnier 	sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset",
1857153e4ad4SBenjamin Mugnier 						     GPIOD_OUT_HIGH);
1858153e4ad4SBenjamin Mugnier 
1859153e4ad4SBenjamin Mugnier 	ret = vgxy61_get_regulators(sensor);
1860153e4ad4SBenjamin Mugnier 	if (ret) {
1861153e4ad4SBenjamin Mugnier 		dev_err(&client->dev, "failed to get regulators %d\n", ret);
1862153e4ad4SBenjamin Mugnier 		return ret;
1863153e4ad4SBenjamin Mugnier 	}
1864153e4ad4SBenjamin Mugnier 
1865153e4ad4SBenjamin Mugnier 	ret = vgxy61_power_on(dev);
1866153e4ad4SBenjamin Mugnier 	if (ret)
1867153e4ad4SBenjamin Mugnier 		return ret;
1868153e4ad4SBenjamin Mugnier 
1869153e4ad4SBenjamin Mugnier 	vgxy61_fill_sensor_param(sensor);
1870153e4ad4SBenjamin Mugnier 	vgxy61_fill_framefmt(sensor, sensor->current_mode, &sensor->fmt,
1871153e4ad4SBenjamin Mugnier 			     VGXY61_MEDIA_BUS_FMT_DEF);
1872153e4ad4SBenjamin Mugnier 
187344b22d45SBenjamin Mugnier 	mutex_init(&sensor->lock);
187444b22d45SBenjamin Mugnier 
1875153e4ad4SBenjamin Mugnier 	ret = vgxy61_update_hdr(sensor, sensor->hdr);
1876153e4ad4SBenjamin Mugnier 	if (ret)
187744b22d45SBenjamin Mugnier 		goto error_power_off;
1878153e4ad4SBenjamin Mugnier 
1879153e4ad4SBenjamin Mugnier 	ret = vgxy61_init_controls(sensor);
1880153e4ad4SBenjamin Mugnier 	if (ret) {
1881153e4ad4SBenjamin Mugnier 		dev_err(&client->dev, "controls initialization failed %d\n",
1882153e4ad4SBenjamin Mugnier 			ret);
1883153e4ad4SBenjamin Mugnier 		goto error_power_off;
1884153e4ad4SBenjamin Mugnier 	}
1885153e4ad4SBenjamin Mugnier 
1886153e4ad4SBenjamin Mugnier 	ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
1887153e4ad4SBenjamin Mugnier 	if (ret) {
1888153e4ad4SBenjamin Mugnier 		dev_err(&client->dev, "pads init failed %d\n", ret);
1889153e4ad4SBenjamin Mugnier 		goto error_handler_free;
1890153e4ad4SBenjamin Mugnier 	}
1891153e4ad4SBenjamin Mugnier 
1892153e4ad4SBenjamin Mugnier 	/* Enable runtime PM and turn off the device */
1893153e4ad4SBenjamin Mugnier 	pm_runtime_set_active(dev);
1894153e4ad4SBenjamin Mugnier 	pm_runtime_enable(dev);
1895153e4ad4SBenjamin Mugnier 	pm_runtime_idle(dev);
1896153e4ad4SBenjamin Mugnier 
1897153e4ad4SBenjamin Mugnier 	ret = v4l2_async_register_subdev(&sensor->sd);
1898153e4ad4SBenjamin Mugnier 	if (ret) {
1899153e4ad4SBenjamin Mugnier 		dev_err(&client->dev, "async subdev register failed %d\n", ret);
1900153e4ad4SBenjamin Mugnier 		goto error_pm_runtime;
1901153e4ad4SBenjamin Mugnier 	}
1902153e4ad4SBenjamin Mugnier 
1903153e4ad4SBenjamin Mugnier 	pm_runtime_set_autosuspend_delay(&client->dev, 1000);
1904153e4ad4SBenjamin Mugnier 	pm_runtime_use_autosuspend(&client->dev);
1905153e4ad4SBenjamin Mugnier 
1906153e4ad4SBenjamin Mugnier 	dev_dbg(&client->dev, "vgxy61 probe successfully\n");
1907153e4ad4SBenjamin Mugnier 
1908153e4ad4SBenjamin Mugnier 	return 0;
1909153e4ad4SBenjamin Mugnier 
1910153e4ad4SBenjamin Mugnier error_pm_runtime:
1911153e4ad4SBenjamin Mugnier 	pm_runtime_disable(&client->dev);
1912153e4ad4SBenjamin Mugnier 	pm_runtime_set_suspended(&client->dev);
1913153e4ad4SBenjamin Mugnier 	media_entity_cleanup(&sensor->sd.entity);
1914153e4ad4SBenjamin Mugnier error_handler_free:
1915153e4ad4SBenjamin Mugnier 	v4l2_ctrl_handler_free(sensor->sd.ctrl_handler);
1916153e4ad4SBenjamin Mugnier error_power_off:
191744b22d45SBenjamin Mugnier 	mutex_destroy(&sensor->lock);
1918153e4ad4SBenjamin Mugnier 	vgxy61_power_off(dev);
1919153e4ad4SBenjamin Mugnier 
1920153e4ad4SBenjamin Mugnier 	return ret;
1921153e4ad4SBenjamin Mugnier }
1922153e4ad4SBenjamin Mugnier 
vgxy61_remove(struct i2c_client * client)1923153e4ad4SBenjamin Mugnier static void vgxy61_remove(struct i2c_client *client)
1924153e4ad4SBenjamin Mugnier {
1925153e4ad4SBenjamin Mugnier 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
1926153e4ad4SBenjamin Mugnier 	struct vgxy61_dev *sensor = to_vgxy61_dev(sd);
1927153e4ad4SBenjamin Mugnier 
1928153e4ad4SBenjamin Mugnier 	v4l2_async_unregister_subdev(&sensor->sd);
1929153e4ad4SBenjamin Mugnier 	mutex_destroy(&sensor->lock);
1930153e4ad4SBenjamin Mugnier 	media_entity_cleanup(&sensor->sd.entity);
1931153e4ad4SBenjamin Mugnier 
1932153e4ad4SBenjamin Mugnier 	pm_runtime_disable(&client->dev);
1933153e4ad4SBenjamin Mugnier 	if (!pm_runtime_status_suspended(&client->dev))
1934153e4ad4SBenjamin Mugnier 		vgxy61_power_off(&client->dev);
1935153e4ad4SBenjamin Mugnier 	pm_runtime_set_suspended(&client->dev);
1936153e4ad4SBenjamin Mugnier }
1937153e4ad4SBenjamin Mugnier 
1938153e4ad4SBenjamin Mugnier static const struct of_device_id vgxy61_dt_ids[] = {
1939153e4ad4SBenjamin Mugnier 	{ .compatible = "st,st-vgxy61" },
1940153e4ad4SBenjamin Mugnier 	{ /* sentinel */ }
1941153e4ad4SBenjamin Mugnier };
1942153e4ad4SBenjamin Mugnier MODULE_DEVICE_TABLE(of, vgxy61_dt_ids);
1943153e4ad4SBenjamin Mugnier 
1944153e4ad4SBenjamin Mugnier static const struct dev_pm_ops vgxy61_pm_ops = {
1945153e4ad4SBenjamin Mugnier 	SET_RUNTIME_PM_OPS(vgxy61_power_off, vgxy61_power_on, NULL)
1946153e4ad4SBenjamin Mugnier };
1947153e4ad4SBenjamin Mugnier 
1948153e4ad4SBenjamin Mugnier static struct i2c_driver vgxy61_i2c_driver = {
1949153e4ad4SBenjamin Mugnier 	.driver = {
1950153e4ad4SBenjamin Mugnier 		.name  = "st-vgxy61",
1951153e4ad4SBenjamin Mugnier 		.of_match_table = vgxy61_dt_ids,
1952153e4ad4SBenjamin Mugnier 		.pm = &vgxy61_pm_ops,
1953153e4ad4SBenjamin Mugnier 	},
1954*aaeb31c0SUwe Kleine-König 	.probe = vgxy61_probe,
1955153e4ad4SBenjamin Mugnier 	.remove = vgxy61_remove,
1956153e4ad4SBenjamin Mugnier };
1957153e4ad4SBenjamin Mugnier 
1958153e4ad4SBenjamin Mugnier module_i2c_driver(vgxy61_i2c_driver);
1959153e4ad4SBenjamin Mugnier 
1960153e4ad4SBenjamin Mugnier MODULE_AUTHOR("Benjamin Mugnier <benjamin.mugnier@foss.st.com>");
1961153e4ad4SBenjamin Mugnier MODULE_AUTHOR("Mickael Guene <mickael.guene@st.com>");
1962153e4ad4SBenjamin Mugnier MODULE_AUTHOR("Sylvain Petinot <sylvain.petinot@foss.st.com>");
1963153e4ad4SBenjamin Mugnier MODULE_DESCRIPTION("VGXY61 camera subdev driver");
1964153e4ad4SBenjamin Mugnier MODULE_LICENSE("GPL");
1965