xref: /openbmc/linux/drivers/media/i2c/ov5675.c (revision 4106cd72)
1bf27502bSShawn Tu // SPDX-License-Identifier: GPL-2.0
2bf27502bSShawn Tu // Copyright (c) 2019 Intel Corporation.
3bf27502bSShawn Tu 
4bf27502bSShawn Tu #include <asm/unaligned.h>
5bf27502bSShawn Tu #include <linux/acpi.h>
649d9ad71SQuentin Schulz #include <linux/clk.h>
7bf27502bSShawn Tu #include <linux/delay.h>
849d9ad71SQuentin Schulz #include <linux/gpio/consumer.h>
9bf27502bSShawn Tu #include <linux/i2c.h>
1049d9ad71SQuentin Schulz #include <linux/mod_devicetable.h>
11bf27502bSShawn Tu #include <linux/module.h>
12bf27502bSShawn Tu #include <linux/pm_runtime.h>
1349d9ad71SQuentin Schulz #include <linux/regulator/consumer.h>
14bf27502bSShawn Tu #include <media/v4l2-ctrls.h>
15bf27502bSShawn Tu #include <media/v4l2-device.h>
16bf27502bSShawn Tu #include <media/v4l2-fwnode.h>
17bf27502bSShawn Tu 
18bf27502bSShawn Tu #define OV5675_REG_VALUE_08BIT		1
19bf27502bSShawn Tu #define OV5675_REG_VALUE_16BIT		2
20bf27502bSShawn Tu #define OV5675_REG_VALUE_24BIT		3
21bf27502bSShawn Tu 
22bf27502bSShawn Tu #define OV5675_LINK_FREQ_450MHZ		450000000ULL
23bf27502bSShawn Tu #define OV5675_SCLK			90000000LL
2449d9ad71SQuentin Schulz #define OV5675_XVCLK_19_2		19200000
25bf27502bSShawn Tu #define OV5675_DATA_LANES		2
26bf27502bSShawn Tu #define OV5675_RGB_DEPTH		10
27bf27502bSShawn Tu 
28bf27502bSShawn Tu #define OV5675_REG_CHIP_ID		0x300a
29bf27502bSShawn Tu #define OV5675_CHIP_ID			0x5675
30bf27502bSShawn Tu 
31bf27502bSShawn Tu #define OV5675_REG_MODE_SELECT		0x0100
32bf27502bSShawn Tu #define OV5675_MODE_STANDBY		0x00
33bf27502bSShawn Tu #define OV5675_MODE_STREAMING		0x01
34bf27502bSShawn Tu 
35bf27502bSShawn Tu /* vertical-timings from sensor */
36bf27502bSShawn Tu #define OV5675_REG_VTS			0x380e
37bf27502bSShawn Tu #define OV5675_VTS_30FPS		0x07e4
38bf27502bSShawn Tu #define OV5675_VTS_30FPS_MIN		0x07e4
39bf27502bSShawn Tu #define OV5675_VTS_MAX			0x7fff
40bf27502bSShawn Tu 
41bf27502bSShawn Tu /* horizontal-timings from sensor */
42bf27502bSShawn Tu #define OV5675_REG_HTS			0x380c
43bf27502bSShawn Tu 
44bf27502bSShawn Tu /* Exposure controls from sensor */
45bf27502bSShawn Tu #define OV5675_REG_EXPOSURE		0x3500
46bf27502bSShawn Tu #define	OV5675_EXPOSURE_MIN		4
47bf27502bSShawn Tu #define OV5675_EXPOSURE_MAX_MARGIN	4
48bf27502bSShawn Tu #define	OV5675_EXPOSURE_STEP		1
49bf27502bSShawn Tu 
50bf27502bSShawn Tu /* Analog gain controls from sensor */
51bf27502bSShawn Tu #define OV5675_REG_ANALOG_GAIN		0x3508
52bf27502bSShawn Tu #define	OV5675_ANAL_GAIN_MIN		128
53bf27502bSShawn Tu #define	OV5675_ANAL_GAIN_MAX		2047
54bf27502bSShawn Tu #define	OV5675_ANAL_GAIN_STEP		1
55bf27502bSShawn Tu 
56bf27502bSShawn Tu /* Digital gain controls from sensor */
5724e9edc1SBingbu Cao #define OV5675_REG_DIGITAL_GAIN		0x350a
58bf27502bSShawn Tu #define OV5675_REG_MWB_R_GAIN		0x5019
59bf27502bSShawn Tu #define OV5675_REG_MWB_G_GAIN		0x501b
60bf27502bSShawn Tu #define OV5675_REG_MWB_B_GAIN		0x501d
6124e9edc1SBingbu Cao #define OV5675_DGTL_GAIN_MIN		1024
62bf27502bSShawn Tu #define OV5675_DGTL_GAIN_MAX		4095
63bf27502bSShawn Tu #define OV5675_DGTL_GAIN_STEP		1
64bf27502bSShawn Tu #define OV5675_DGTL_GAIN_DEFAULT	1024
65bf27502bSShawn Tu 
6624e9edc1SBingbu Cao /* Group Access */
6724e9edc1SBingbu Cao #define OV5675_REG_GROUP_ACCESS		0x3208
6824e9edc1SBingbu Cao #define OV5675_GROUP_HOLD_START		0x0
6924e9edc1SBingbu Cao #define OV5675_GROUP_HOLD_END		0x10
7024e9edc1SBingbu Cao #define OV5675_GROUP_HOLD_LAUNCH	0xa0
7124e9edc1SBingbu Cao 
72bf27502bSShawn Tu /* Test Pattern Control */
73bf27502bSShawn Tu #define OV5675_REG_TEST_PATTERN		0x4503
74bf27502bSShawn Tu #define OV5675_TEST_PATTERN_ENABLE	BIT(7)
75bf27502bSShawn Tu #define OV5675_TEST_PATTERN_BAR_SHIFT	2
76bf27502bSShawn Tu 
77e8882e1bSShawn Tu /* Flip Mirror Controls from sensor */
78e8882e1bSShawn Tu #define OV5675_REG_FORMAT1		0x3820
79e8882e1bSShawn Tu #define OV5675_REG_FORMAT2		0x373d
80e8882e1bSShawn Tu 
81bf27502bSShawn Tu #define to_ov5675(_sd)			container_of(_sd, struct ov5675, sd)
82bf27502bSShawn Tu 
8349d9ad71SQuentin Schulz static const char * const ov5675_supply_names[] = {
8449d9ad71SQuentin Schulz 	"avdd",		/* Analog power */
8549d9ad71SQuentin Schulz 	"dovdd",	/* Digital I/O power */
8649d9ad71SQuentin Schulz 	"dvdd",		/* Digital core power */
8749d9ad71SQuentin Schulz };
8849d9ad71SQuentin Schulz 
8949d9ad71SQuentin Schulz #define OV5675_NUM_SUPPLIES	ARRAY_SIZE(ov5675_supply_names)
9049d9ad71SQuentin Schulz 
91bf27502bSShawn Tu enum {
92bf27502bSShawn Tu 	OV5675_LINK_FREQ_900MBPS,
93bf27502bSShawn Tu };
94bf27502bSShawn Tu 
95bf27502bSShawn Tu struct ov5675_reg {
96bf27502bSShawn Tu 	u16 address;
97bf27502bSShawn Tu 	u8 val;
98bf27502bSShawn Tu };
99bf27502bSShawn Tu 
100bf27502bSShawn Tu struct ov5675_reg_list {
101bf27502bSShawn Tu 	u32 num_of_regs;
102bf27502bSShawn Tu 	const struct ov5675_reg *regs;
103bf27502bSShawn Tu };
104bf27502bSShawn Tu 
105bf27502bSShawn Tu struct ov5675_link_freq_config {
106bf27502bSShawn Tu 	const struct ov5675_reg_list reg_list;
107bf27502bSShawn Tu };
108bf27502bSShawn Tu 
109bf27502bSShawn Tu struct ov5675_mode {
110bf27502bSShawn Tu 	/* Frame width in pixels */
111bf27502bSShawn Tu 	u32 width;
112bf27502bSShawn Tu 
113bf27502bSShawn Tu 	/* Frame height in pixels */
114bf27502bSShawn Tu 	u32 height;
115bf27502bSShawn Tu 
116bf27502bSShawn Tu 	/* Horizontal timining size */
117bf27502bSShawn Tu 	u32 hts;
118bf27502bSShawn Tu 
119bf27502bSShawn Tu 	/* Default vertical timining size */
120bf27502bSShawn Tu 	u32 vts_def;
121bf27502bSShawn Tu 
122bf27502bSShawn Tu 	/* Min vertical timining size */
123bf27502bSShawn Tu 	u32 vts_min;
124bf27502bSShawn Tu 
125bf27502bSShawn Tu 	/* Link frequency needed for this resolution */
126bf27502bSShawn Tu 	u32 link_freq_index;
127bf27502bSShawn Tu 
128bf27502bSShawn Tu 	/* Sensor register settings for this resolution */
129bf27502bSShawn Tu 	const struct ov5675_reg_list reg_list;
130bf27502bSShawn Tu };
131bf27502bSShawn Tu 
132bf27502bSShawn Tu static const struct ov5675_reg mipi_data_rate_900mbps[] = {
133bf27502bSShawn Tu 	{0x0103, 0x01},
134bf27502bSShawn Tu 	{0x0100, 0x00},
135bf27502bSShawn Tu 	{0x0300, 0x04},
136bf27502bSShawn Tu 	{0x0302, 0x8d},
137bf27502bSShawn Tu 	{0x0303, 0x00},
138bf27502bSShawn Tu 	{0x030d, 0x26},
139bf27502bSShawn Tu };
140bf27502bSShawn Tu 
141bf27502bSShawn Tu static const struct ov5675_reg mode_2592x1944_regs[] = {
142bf27502bSShawn Tu 	{0x3002, 0x21},
143bf27502bSShawn Tu 	{0x3107, 0x23},
144bf27502bSShawn Tu 	{0x3501, 0x20},
145bf27502bSShawn Tu 	{0x3503, 0x0c},
146bf27502bSShawn Tu 	{0x3508, 0x03},
147bf27502bSShawn Tu 	{0x3509, 0x00},
148bf27502bSShawn Tu 	{0x3600, 0x66},
149bf27502bSShawn Tu 	{0x3602, 0x30},
150bf27502bSShawn Tu 	{0x3610, 0xa5},
151bf27502bSShawn Tu 	{0x3612, 0x93},
152bf27502bSShawn Tu 	{0x3620, 0x80},
153bf27502bSShawn Tu 	{0x3642, 0x0e},
154bf27502bSShawn Tu 	{0x3661, 0x00},
155bf27502bSShawn Tu 	{0x3662, 0x10},
156bf27502bSShawn Tu 	{0x3664, 0xf3},
157bf27502bSShawn Tu 	{0x3665, 0x9e},
158bf27502bSShawn Tu 	{0x3667, 0xa5},
159bf27502bSShawn Tu 	{0x366e, 0x55},
160bf27502bSShawn Tu 	{0x366f, 0x55},
161bf27502bSShawn Tu 	{0x3670, 0x11},
162bf27502bSShawn Tu 	{0x3671, 0x11},
163bf27502bSShawn Tu 	{0x3672, 0x11},
164bf27502bSShawn Tu 	{0x3673, 0x11},
165bf27502bSShawn Tu 	{0x3714, 0x24},
166bf27502bSShawn Tu 	{0x371a, 0x3e},
167bf27502bSShawn Tu 	{0x3733, 0x10},
168bf27502bSShawn Tu 	{0x3734, 0x00},
169bf27502bSShawn Tu 	{0x373d, 0x24},
170bf27502bSShawn Tu 	{0x3764, 0x20},
171bf27502bSShawn Tu 	{0x3765, 0x20},
172bf27502bSShawn Tu 	{0x3766, 0x12},
173bf27502bSShawn Tu 	{0x37a1, 0x14},
174bf27502bSShawn Tu 	{0x37a8, 0x1c},
175bf27502bSShawn Tu 	{0x37ab, 0x0f},
176bf27502bSShawn Tu 	{0x37c2, 0x04},
177bf27502bSShawn Tu 	{0x37cb, 0x00},
178bf27502bSShawn Tu 	{0x37cc, 0x00},
179bf27502bSShawn Tu 	{0x37cd, 0x00},
180bf27502bSShawn Tu 	{0x37ce, 0x00},
181bf27502bSShawn Tu 	{0x37d8, 0x02},
182bf27502bSShawn Tu 	{0x37d9, 0x08},
183bf27502bSShawn Tu 	{0x37dc, 0x04},
184bf27502bSShawn Tu 	{0x3800, 0x00},
185bf27502bSShawn Tu 	{0x3801, 0x00},
186bf27502bSShawn Tu 	{0x3802, 0x00},
187bf27502bSShawn Tu 	{0x3803, 0x04},
188bf27502bSShawn Tu 	{0x3804, 0x0a},
189bf27502bSShawn Tu 	{0x3805, 0x3f},
190bf27502bSShawn Tu 	{0x3806, 0x07},
191bf27502bSShawn Tu 	{0x3807, 0xb3},
192bf27502bSShawn Tu 	{0x3808, 0x0a},
193bf27502bSShawn Tu 	{0x3809, 0x20},
194bf27502bSShawn Tu 	{0x380a, 0x07},
195bf27502bSShawn Tu 	{0x380b, 0x98},
196bf27502bSShawn Tu 	{0x380c, 0x02},
197bf27502bSShawn Tu 	{0x380d, 0xee},
198bf27502bSShawn Tu 	{0x380e, 0x07},
199bf27502bSShawn Tu 	{0x380f, 0xe4},
200bf27502bSShawn Tu 	{0x3811, 0x10},
201bf27502bSShawn Tu 	{0x3813, 0x0d},
202bf27502bSShawn Tu 	{0x3814, 0x01},
203bf27502bSShawn Tu 	{0x3815, 0x01},
204bf27502bSShawn Tu 	{0x3816, 0x01},
205bf27502bSShawn Tu 	{0x3817, 0x01},
206bf27502bSShawn Tu 	{0x381e, 0x02},
207bf27502bSShawn Tu 	{0x3820, 0x88},
208bf27502bSShawn Tu 	{0x3821, 0x01},
209bf27502bSShawn Tu 	{0x3832, 0x04},
210bf27502bSShawn Tu 	{0x3c80, 0x01},
211bf27502bSShawn Tu 	{0x3c82, 0x00},
212bf27502bSShawn Tu 	{0x3c83, 0xc8},
213bf27502bSShawn Tu 	{0x3c8c, 0x0f},
214bf27502bSShawn Tu 	{0x3c8d, 0xa0},
215bf27502bSShawn Tu 	{0x3c90, 0x07},
216bf27502bSShawn Tu 	{0x3c91, 0x00},
217bf27502bSShawn Tu 	{0x3c92, 0x00},
218bf27502bSShawn Tu 	{0x3c93, 0x00},
219bf27502bSShawn Tu 	{0x3c94, 0xd0},
220bf27502bSShawn Tu 	{0x3c95, 0x50},
221bf27502bSShawn Tu 	{0x3c96, 0x35},
222bf27502bSShawn Tu 	{0x3c97, 0x00},
223bf27502bSShawn Tu 	{0x4001, 0xe0},
224bf27502bSShawn Tu 	{0x4008, 0x02},
225bf27502bSShawn Tu 	{0x4009, 0x0d},
226bf27502bSShawn Tu 	{0x400f, 0x80},
227bf27502bSShawn Tu 	{0x4013, 0x02},
228bf27502bSShawn Tu 	{0x4040, 0x00},
229bf27502bSShawn Tu 	{0x4041, 0x07},
230bf27502bSShawn Tu 	{0x404c, 0x50},
231bf27502bSShawn Tu 	{0x404e, 0x20},
232bf27502bSShawn Tu 	{0x4500, 0x06},
233bf27502bSShawn Tu 	{0x4503, 0x00},
234bf27502bSShawn Tu 	{0x450a, 0x04},
235bf27502bSShawn Tu 	{0x4809, 0x04},
236bf27502bSShawn Tu 	{0x480c, 0x12},
237bf27502bSShawn Tu 	{0x4819, 0x70},
238bf27502bSShawn Tu 	{0x4825, 0x32},
239bf27502bSShawn Tu 	{0x4826, 0x32},
240bf27502bSShawn Tu 	{0x482a, 0x06},
241bf27502bSShawn Tu 	{0x4833, 0x08},
242bf27502bSShawn Tu 	{0x4837, 0x0d},
243bf27502bSShawn Tu 	{0x5000, 0x77},
244bf27502bSShawn Tu 	{0x5b00, 0x01},
245bf27502bSShawn Tu 	{0x5b01, 0x10},
246bf27502bSShawn Tu 	{0x5b02, 0x01},
247bf27502bSShawn Tu 	{0x5b03, 0xdb},
248bf27502bSShawn Tu 	{0x5b05, 0x6c},
249bf27502bSShawn Tu 	{0x5e10, 0xfc},
250bf27502bSShawn Tu 	{0x3500, 0x00},
251bf27502bSShawn Tu 	{0x3501, 0x3E},
252bf27502bSShawn Tu 	{0x3502, 0x60},
253bf27502bSShawn Tu 	{0x3503, 0x08},
254bf27502bSShawn Tu 	{0x3508, 0x04},
255bf27502bSShawn Tu 	{0x3509, 0x00},
256bf27502bSShawn Tu 	{0x3832, 0x48},
257bf27502bSShawn Tu 	{0x5780, 0x3e},
258bf27502bSShawn Tu 	{0x5781, 0x0f},
259bf27502bSShawn Tu 	{0x5782, 0x44},
260bf27502bSShawn Tu 	{0x5783, 0x02},
261bf27502bSShawn Tu 	{0x5784, 0x01},
262bf27502bSShawn Tu 	{0x5785, 0x01},
263bf27502bSShawn Tu 	{0x5786, 0x00},
264bf27502bSShawn Tu 	{0x5787, 0x04},
265bf27502bSShawn Tu 	{0x5788, 0x02},
266bf27502bSShawn Tu 	{0x5789, 0x0f},
267bf27502bSShawn Tu 	{0x578a, 0xfd},
268bf27502bSShawn Tu 	{0x578b, 0xf5},
269bf27502bSShawn Tu 	{0x578c, 0xf5},
270bf27502bSShawn Tu 	{0x578d, 0x03},
271bf27502bSShawn Tu 	{0x578e, 0x08},
272bf27502bSShawn Tu 	{0x578f, 0x0c},
273bf27502bSShawn Tu 	{0x5790, 0x08},
274bf27502bSShawn Tu 	{0x5791, 0x06},
275bf27502bSShawn Tu 	{0x5792, 0x00},
276bf27502bSShawn Tu 	{0x5793, 0x52},
277bf27502bSShawn Tu 	{0x5794, 0xa3},
278bf27502bSShawn Tu 	{0x4003, 0x40},
279bf27502bSShawn Tu 	{0x3107, 0x01},
280bf27502bSShawn Tu 	{0x3c80, 0x08},
281bf27502bSShawn Tu 	{0x3c83, 0xb1},
282bf27502bSShawn Tu 	{0x3c8c, 0x10},
283bf27502bSShawn Tu 	{0x3c8d, 0x00},
284bf27502bSShawn Tu 	{0x3c90, 0x00},
285bf27502bSShawn Tu 	{0x3c94, 0x00},
286bf27502bSShawn Tu 	{0x3c95, 0x00},
287bf27502bSShawn Tu 	{0x3c96, 0x00},
288bf27502bSShawn Tu 	{0x37cb, 0x09},
289bf27502bSShawn Tu 	{0x37cc, 0x15},
290bf27502bSShawn Tu 	{0x37cd, 0x1f},
291bf27502bSShawn Tu 	{0x37ce, 0x1f},
292bf27502bSShawn Tu };
293bf27502bSShawn Tu 
294bf27502bSShawn Tu static const struct ov5675_reg mode_1296x972_regs[] = {
295bf27502bSShawn Tu 	{0x3002, 0x21},
296bf27502bSShawn Tu 	{0x3107, 0x23},
297bf27502bSShawn Tu 	{0x3501, 0x20},
298bf27502bSShawn Tu 	{0x3503, 0x0c},
299bf27502bSShawn Tu 	{0x3508, 0x03},
300bf27502bSShawn Tu 	{0x3509, 0x00},
301bf27502bSShawn Tu 	{0x3600, 0x66},
302bf27502bSShawn Tu 	{0x3602, 0x30},
303bf27502bSShawn Tu 	{0x3610, 0xa5},
304bf27502bSShawn Tu 	{0x3612, 0x93},
305bf27502bSShawn Tu 	{0x3620, 0x80},
306bf27502bSShawn Tu 	{0x3642, 0x0e},
307bf27502bSShawn Tu 	{0x3661, 0x00},
308bf27502bSShawn Tu 	{0x3662, 0x08},
309bf27502bSShawn Tu 	{0x3664, 0xf3},
310bf27502bSShawn Tu 	{0x3665, 0x9e},
311bf27502bSShawn Tu 	{0x3667, 0xa5},
312bf27502bSShawn Tu 	{0x366e, 0x55},
313bf27502bSShawn Tu 	{0x366f, 0x55},
314bf27502bSShawn Tu 	{0x3670, 0x11},
315bf27502bSShawn Tu 	{0x3671, 0x11},
316bf27502bSShawn Tu 	{0x3672, 0x11},
317bf27502bSShawn Tu 	{0x3673, 0x11},
318bf27502bSShawn Tu 	{0x3714, 0x28},
319bf27502bSShawn Tu 	{0x371a, 0x3e},
320bf27502bSShawn Tu 	{0x3733, 0x10},
321bf27502bSShawn Tu 	{0x3734, 0x00},
322bf27502bSShawn Tu 	{0x373d, 0x24},
323bf27502bSShawn Tu 	{0x3764, 0x20},
324bf27502bSShawn Tu 	{0x3765, 0x20},
325bf27502bSShawn Tu 	{0x3766, 0x12},
326bf27502bSShawn Tu 	{0x37a1, 0x14},
327bf27502bSShawn Tu 	{0x37a8, 0x1c},
328bf27502bSShawn Tu 	{0x37ab, 0x0f},
329bf27502bSShawn Tu 	{0x37c2, 0x14},
330bf27502bSShawn Tu 	{0x37cb, 0x00},
331bf27502bSShawn Tu 	{0x37cc, 0x00},
332bf27502bSShawn Tu 	{0x37cd, 0x00},
333bf27502bSShawn Tu 	{0x37ce, 0x00},
334bf27502bSShawn Tu 	{0x37d8, 0x02},
335bf27502bSShawn Tu 	{0x37d9, 0x04},
336bf27502bSShawn Tu 	{0x37dc, 0x04},
337bf27502bSShawn Tu 	{0x3800, 0x00},
338bf27502bSShawn Tu 	{0x3801, 0x00},
339bf27502bSShawn Tu 	{0x3802, 0x00},
340e8882e1bSShawn Tu 	{0x3803, 0x00},
341bf27502bSShawn Tu 	{0x3804, 0x0a},
342bf27502bSShawn Tu 	{0x3805, 0x3f},
343e8882e1bSShawn Tu 	{0x3806, 0x07},
344e8882e1bSShawn Tu 	{0x3807, 0xb7},
345bf27502bSShawn Tu 	{0x3808, 0x05},
346e8882e1bSShawn Tu 	{0x3809, 0x10},
347e8882e1bSShawn Tu 	{0x380a, 0x03},
348e8882e1bSShawn Tu 	{0x380b, 0xcc},
349bf27502bSShawn Tu 	{0x380c, 0x02},
350bf27502bSShawn Tu 	{0x380d, 0xee},
351bf27502bSShawn Tu 	{0x380e, 0x07},
352e8882e1bSShawn Tu 	{0x380f, 0xd0},
353e8882e1bSShawn Tu 	{0x3811, 0x08},
354e8882e1bSShawn Tu 	{0x3813, 0x0d},
355bf27502bSShawn Tu 	{0x3814, 0x03},
356bf27502bSShawn Tu 	{0x3815, 0x01},
357bf27502bSShawn Tu 	{0x3816, 0x03},
358bf27502bSShawn Tu 	{0x3817, 0x01},
359bf27502bSShawn Tu 	{0x381e, 0x02},
360bf27502bSShawn Tu 	{0x3820, 0x8b},
361bf27502bSShawn Tu 	{0x3821, 0x01},
362bf27502bSShawn Tu 	{0x3832, 0x04},
363bf27502bSShawn Tu 	{0x3c80, 0x01},
364bf27502bSShawn Tu 	{0x3c82, 0x00},
365bf27502bSShawn Tu 	{0x3c83, 0xc8},
366bf27502bSShawn Tu 	{0x3c8c, 0x0f},
367bf27502bSShawn Tu 	{0x3c8d, 0xa0},
368bf27502bSShawn Tu 	{0x3c90, 0x07},
369bf27502bSShawn Tu 	{0x3c91, 0x00},
370bf27502bSShawn Tu 	{0x3c92, 0x00},
371bf27502bSShawn Tu 	{0x3c93, 0x00},
372bf27502bSShawn Tu 	{0x3c94, 0xd0},
373bf27502bSShawn Tu 	{0x3c95, 0x50},
374bf27502bSShawn Tu 	{0x3c96, 0x35},
375bf27502bSShawn Tu 	{0x3c97, 0x00},
376bf27502bSShawn Tu 	{0x4001, 0xe0},
377bf27502bSShawn Tu 	{0x4008, 0x00},
378bf27502bSShawn Tu 	{0x4009, 0x07},
379bf27502bSShawn Tu 	{0x400f, 0x80},
380bf27502bSShawn Tu 	{0x4013, 0x02},
381bf27502bSShawn Tu 	{0x4040, 0x00},
382bf27502bSShawn Tu 	{0x4041, 0x03},
383bf27502bSShawn Tu 	{0x404c, 0x50},
384bf27502bSShawn Tu 	{0x404e, 0x20},
385bf27502bSShawn Tu 	{0x4500, 0x06},
386bf27502bSShawn Tu 	{0x4503, 0x00},
387bf27502bSShawn Tu 	{0x450a, 0x04},
388bf27502bSShawn Tu 	{0x4809, 0x04},
389bf27502bSShawn Tu 	{0x480c, 0x12},
390bf27502bSShawn Tu 	{0x4819, 0x70},
391bf27502bSShawn Tu 	{0x4825, 0x32},
392bf27502bSShawn Tu 	{0x4826, 0x32},
393bf27502bSShawn Tu 	{0x482a, 0x06},
394bf27502bSShawn Tu 	{0x4833, 0x08},
395bf27502bSShawn Tu 	{0x4837, 0x0d},
396bf27502bSShawn Tu 	{0x5000, 0x77},
397bf27502bSShawn Tu 	{0x5b00, 0x01},
398bf27502bSShawn Tu 	{0x5b01, 0x10},
399bf27502bSShawn Tu 	{0x5b02, 0x01},
400bf27502bSShawn Tu 	{0x5b03, 0xdb},
401bf27502bSShawn Tu 	{0x5b05, 0x6c},
402bf27502bSShawn Tu 	{0x5e10, 0xfc},
403bf27502bSShawn Tu 	{0x3500, 0x00},
404bf27502bSShawn Tu 	{0x3501, 0x1F},
405bf27502bSShawn Tu 	{0x3502, 0x20},
406bf27502bSShawn Tu 	{0x3503, 0x08},
407bf27502bSShawn Tu 	{0x3508, 0x04},
408bf27502bSShawn Tu 	{0x3509, 0x00},
409bf27502bSShawn Tu 	{0x3832, 0x48},
410bf27502bSShawn Tu 	{0x5780, 0x3e},
411bf27502bSShawn Tu 	{0x5781, 0x0f},
412bf27502bSShawn Tu 	{0x5782, 0x44},
413bf27502bSShawn Tu 	{0x5783, 0x02},
414bf27502bSShawn Tu 	{0x5784, 0x01},
415bf27502bSShawn Tu 	{0x5785, 0x01},
416bf27502bSShawn Tu 	{0x5786, 0x00},
417bf27502bSShawn Tu 	{0x5787, 0x04},
418bf27502bSShawn Tu 	{0x5788, 0x02},
419bf27502bSShawn Tu 	{0x5789, 0x0f},
420bf27502bSShawn Tu 	{0x578a, 0xfd},
421bf27502bSShawn Tu 	{0x578b, 0xf5},
422bf27502bSShawn Tu 	{0x578c, 0xf5},
423bf27502bSShawn Tu 	{0x578d, 0x03},
424bf27502bSShawn Tu 	{0x578e, 0x08},
425bf27502bSShawn Tu 	{0x578f, 0x0c},
426bf27502bSShawn Tu 	{0x5790, 0x08},
427bf27502bSShawn Tu 	{0x5791, 0x06},
428bf27502bSShawn Tu 	{0x5792, 0x00},
429bf27502bSShawn Tu 	{0x5793, 0x52},
430bf27502bSShawn Tu 	{0x5794, 0xa3},
431bf27502bSShawn Tu 	{0x4003, 0x40},
432bf27502bSShawn Tu 	{0x3107, 0x01},
433bf27502bSShawn Tu 	{0x3c80, 0x08},
434bf27502bSShawn Tu 	{0x3c83, 0xb1},
435bf27502bSShawn Tu 	{0x3c8c, 0x10},
436bf27502bSShawn Tu 	{0x3c8d, 0x00},
437bf27502bSShawn Tu 	{0x3c90, 0x00},
438bf27502bSShawn Tu 	{0x3c94, 0x00},
439bf27502bSShawn Tu 	{0x3c95, 0x00},
440bf27502bSShawn Tu 	{0x3c96, 0x00},
441bf27502bSShawn Tu 	{0x37cb, 0x09},
442bf27502bSShawn Tu 	{0x37cc, 0x15},
443bf27502bSShawn Tu 	{0x37cd, 0x1f},
444bf27502bSShawn Tu 	{0x37ce, 0x1f},
445bf27502bSShawn Tu };
446bf27502bSShawn Tu 
447bf27502bSShawn Tu static const char * const ov5675_test_pattern_menu[] = {
448bf27502bSShawn Tu 	"Disabled",
449bf27502bSShawn Tu 	"Standard Color Bar",
450bf27502bSShawn Tu 	"Top-Bottom Darker Color Bar",
451bf27502bSShawn Tu 	"Right-Left Darker Color Bar",
452bf27502bSShawn Tu 	"Bottom-Top Darker Color Bar"
453bf27502bSShawn Tu };
454bf27502bSShawn Tu 
455bf27502bSShawn Tu static const s64 link_freq_menu_items[] = {
456bf27502bSShawn Tu 	OV5675_LINK_FREQ_450MHZ,
457bf27502bSShawn Tu };
458bf27502bSShawn Tu 
459bf27502bSShawn Tu static const struct ov5675_link_freq_config link_freq_configs[] = {
460bf27502bSShawn Tu 	[OV5675_LINK_FREQ_900MBPS] = {
461bf27502bSShawn Tu 		.reg_list = {
462bf27502bSShawn Tu 			.num_of_regs = ARRAY_SIZE(mipi_data_rate_900mbps),
463bf27502bSShawn Tu 			.regs = mipi_data_rate_900mbps,
464bf27502bSShawn Tu 		}
465bf27502bSShawn Tu 	}
466bf27502bSShawn Tu };
467bf27502bSShawn Tu 
468bf27502bSShawn Tu static const struct ov5675_mode supported_modes[] = {
469bf27502bSShawn Tu 	{
470bf27502bSShawn Tu 		.width = 2592,
471bf27502bSShawn Tu 		.height = 1944,
472bf27502bSShawn Tu 		.hts = 1500,
473bf27502bSShawn Tu 		.vts_def = OV5675_VTS_30FPS,
474bf27502bSShawn Tu 		.vts_min = OV5675_VTS_30FPS_MIN,
475bf27502bSShawn Tu 		.reg_list = {
476bf27502bSShawn Tu 			.num_of_regs = ARRAY_SIZE(mode_2592x1944_regs),
477bf27502bSShawn Tu 			.regs = mode_2592x1944_regs,
478bf27502bSShawn Tu 		},
479bf27502bSShawn Tu 		.link_freq_index = OV5675_LINK_FREQ_900MBPS,
480bf27502bSShawn Tu 	},
481bf27502bSShawn Tu 	{
482bf27502bSShawn Tu 		.width = 1296,
483bf27502bSShawn Tu 		.height = 972,
484bf27502bSShawn Tu 		.hts = 1500,
485bf27502bSShawn Tu 		.vts_def = OV5675_VTS_30FPS,
486bf27502bSShawn Tu 		.vts_min = OV5675_VTS_30FPS_MIN,
487bf27502bSShawn Tu 		.reg_list = {
488bf27502bSShawn Tu 			.num_of_regs = ARRAY_SIZE(mode_1296x972_regs),
489bf27502bSShawn Tu 			.regs = mode_1296x972_regs,
490bf27502bSShawn Tu 		},
491bf27502bSShawn Tu 		.link_freq_index = OV5675_LINK_FREQ_900MBPS,
492bf27502bSShawn Tu 	}
493bf27502bSShawn Tu };
494bf27502bSShawn Tu 
495bf27502bSShawn Tu struct ov5675 {
496bf27502bSShawn Tu 	struct v4l2_subdev sd;
497bf27502bSShawn Tu 	struct media_pad pad;
498bf27502bSShawn Tu 	struct v4l2_ctrl_handler ctrl_handler;
49949d9ad71SQuentin Schulz 	struct clk *xvclk;
50049d9ad71SQuentin Schulz 	struct gpio_desc *reset_gpio;
50149d9ad71SQuentin Schulz 	struct regulator_bulk_data supplies[OV5675_NUM_SUPPLIES];
502bf27502bSShawn Tu 
503bf27502bSShawn Tu 	/* V4L2 Controls */
504bf27502bSShawn Tu 	struct v4l2_ctrl *link_freq;
505bf27502bSShawn Tu 	struct v4l2_ctrl *pixel_rate;
506bf27502bSShawn Tu 	struct v4l2_ctrl *vblank;
507bf27502bSShawn Tu 	struct v4l2_ctrl *hblank;
508bf27502bSShawn Tu 	struct v4l2_ctrl *exposure;
509bf27502bSShawn Tu 
510bf27502bSShawn Tu 	/* Current mode */
511bf27502bSShawn Tu 	const struct ov5675_mode *cur_mode;
512bf27502bSShawn Tu 
513bf27502bSShawn Tu 	/* To serialize asynchronus callbacks */
514bf27502bSShawn Tu 	struct mutex mutex;
515bf27502bSShawn Tu 
516bf27502bSShawn Tu 	/* Streaming on/off */
517bf27502bSShawn Tu 	bool streaming;
5185525fd86SBingbu Cao 
5195525fd86SBingbu Cao 	/* True if the device has been identified */
5205525fd86SBingbu Cao 	bool identified;
521bf27502bSShawn Tu };
522bf27502bSShawn Tu 
to_pixel_rate(u32 f_index)523bf27502bSShawn Tu static u64 to_pixel_rate(u32 f_index)
524bf27502bSShawn Tu {
525bf27502bSShawn Tu 	u64 pixel_rate = link_freq_menu_items[f_index] * 2 * OV5675_DATA_LANES;
526bf27502bSShawn Tu 
527bf27502bSShawn Tu 	do_div(pixel_rate, OV5675_RGB_DEPTH);
528bf27502bSShawn Tu 
529bf27502bSShawn Tu 	return pixel_rate;
530bf27502bSShawn Tu }
531bf27502bSShawn Tu 
to_pixels_per_line(u32 hts,u32 f_index)532bf27502bSShawn Tu static u64 to_pixels_per_line(u32 hts, u32 f_index)
533bf27502bSShawn Tu {
534bf27502bSShawn Tu 	u64 ppl = hts * to_pixel_rate(f_index);
535bf27502bSShawn Tu 
536bf27502bSShawn Tu 	do_div(ppl, OV5675_SCLK);
537bf27502bSShawn Tu 
538bf27502bSShawn Tu 	return ppl;
539bf27502bSShawn Tu }
540bf27502bSShawn Tu 
ov5675_read_reg(struct ov5675 * ov5675,u16 reg,u16 len,u32 * val)541bf27502bSShawn Tu static int ov5675_read_reg(struct ov5675 *ov5675, u16 reg, u16 len, u32 *val)
542bf27502bSShawn Tu {
543bf27502bSShawn Tu 	struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd);
544bf27502bSShawn Tu 	struct i2c_msg msgs[2];
545bf27502bSShawn Tu 	u8 addr_buf[2];
546bf27502bSShawn Tu 	u8 data_buf[4] = {0};
547bf27502bSShawn Tu 	int ret;
548bf27502bSShawn Tu 
549bf27502bSShawn Tu 	if (len > 4)
550bf27502bSShawn Tu 		return -EINVAL;
551bf27502bSShawn Tu 
552bf27502bSShawn Tu 	put_unaligned_be16(reg, addr_buf);
553bf27502bSShawn Tu 	msgs[0].addr = client->addr;
554bf27502bSShawn Tu 	msgs[0].flags = 0;
555bf27502bSShawn Tu 	msgs[0].len = sizeof(addr_buf);
556bf27502bSShawn Tu 	msgs[0].buf = addr_buf;
557bf27502bSShawn Tu 	msgs[1].addr = client->addr;
558bf27502bSShawn Tu 	msgs[1].flags = I2C_M_RD;
559bf27502bSShawn Tu 	msgs[1].len = len;
560bf27502bSShawn Tu 	msgs[1].buf = &data_buf[4 - len];
561bf27502bSShawn Tu 
562bf27502bSShawn Tu 	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
563bf27502bSShawn Tu 	if (ret != ARRAY_SIZE(msgs))
564bf27502bSShawn Tu 		return -EIO;
565bf27502bSShawn Tu 
566bf27502bSShawn Tu 	*val = get_unaligned_be32(data_buf);
567bf27502bSShawn Tu 
568bf27502bSShawn Tu 	return 0;
569bf27502bSShawn Tu }
570bf27502bSShawn Tu 
ov5675_write_reg(struct ov5675 * ov5675,u16 reg,u16 len,u32 val)571bf27502bSShawn Tu static int ov5675_write_reg(struct ov5675 *ov5675, u16 reg, u16 len, u32 val)
572bf27502bSShawn Tu {
573bf27502bSShawn Tu 	struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd);
574bf27502bSShawn Tu 	u8 buf[6];
575bf27502bSShawn Tu 
576bf27502bSShawn Tu 	if (len > 4)
577bf27502bSShawn Tu 		return -EINVAL;
578bf27502bSShawn Tu 
579bf27502bSShawn Tu 	put_unaligned_be16(reg, buf);
580bf27502bSShawn Tu 	put_unaligned_be32(val << 8 * (4 - len), buf + 2);
581bf27502bSShawn Tu 	if (i2c_master_send(client, buf, len + 2) != len + 2)
582bf27502bSShawn Tu 		return -EIO;
583bf27502bSShawn Tu 
584bf27502bSShawn Tu 	return 0;
585bf27502bSShawn Tu }
586bf27502bSShawn Tu 
ov5675_write_reg_list(struct ov5675 * ov5675,const struct ov5675_reg_list * r_list)587bf27502bSShawn Tu static int ov5675_write_reg_list(struct ov5675 *ov5675,
588bf27502bSShawn Tu 				 const struct ov5675_reg_list *r_list)
589bf27502bSShawn Tu {
590bf27502bSShawn Tu 	struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd);
591bf27502bSShawn Tu 	unsigned int i;
592bf27502bSShawn Tu 	int ret;
593bf27502bSShawn Tu 
594bf27502bSShawn Tu 	for (i = 0; i < r_list->num_of_regs; i++) {
595bf27502bSShawn Tu 		ret = ov5675_write_reg(ov5675, r_list->regs[i].address, 1,
596bf27502bSShawn Tu 				       r_list->regs[i].val);
597bf27502bSShawn Tu 		if (ret) {
598bf27502bSShawn Tu 			dev_err_ratelimited(&client->dev,
599bf27502bSShawn Tu 				    "failed to write reg 0x%4.4x. error = %d",
600bf27502bSShawn Tu 				    r_list->regs[i].address, ret);
601bf27502bSShawn Tu 			return ret;
602bf27502bSShawn Tu 		}
603bf27502bSShawn Tu 	}
604bf27502bSShawn Tu 
605bf27502bSShawn Tu 	return 0;
606bf27502bSShawn Tu }
607bf27502bSShawn Tu 
ov5675_update_digital_gain(struct ov5675 * ov5675,u32 d_gain)608bf27502bSShawn Tu static int ov5675_update_digital_gain(struct ov5675 *ov5675, u32 d_gain)
609bf27502bSShawn Tu {
610bf27502bSShawn Tu 	int ret;
611bf27502bSShawn Tu 
61224e9edc1SBingbu Cao 	ret = ov5675_write_reg(ov5675, OV5675_REG_GROUP_ACCESS,
61324e9edc1SBingbu Cao 			       OV5675_REG_VALUE_08BIT,
61424e9edc1SBingbu Cao 			       OV5675_GROUP_HOLD_START);
61524e9edc1SBingbu Cao 	if (ret)
61624e9edc1SBingbu Cao 		return ret;
61724e9edc1SBingbu Cao 
618bf27502bSShawn Tu 	ret = ov5675_write_reg(ov5675, OV5675_REG_MWB_R_GAIN,
619bf27502bSShawn Tu 			       OV5675_REG_VALUE_16BIT, d_gain);
620bf27502bSShawn Tu 	if (ret)
621bf27502bSShawn Tu 		return ret;
622bf27502bSShawn Tu 
623bf27502bSShawn Tu 	ret = ov5675_write_reg(ov5675, OV5675_REG_MWB_G_GAIN,
624bf27502bSShawn Tu 			       OV5675_REG_VALUE_16BIT, d_gain);
625bf27502bSShawn Tu 	if (ret)
626bf27502bSShawn Tu 		return ret;
627bf27502bSShawn Tu 
62824e9edc1SBingbu Cao 	ret = ov5675_write_reg(ov5675, OV5675_REG_MWB_B_GAIN,
629bf27502bSShawn Tu 			       OV5675_REG_VALUE_16BIT, d_gain);
63024e9edc1SBingbu Cao 	if (ret)
63124e9edc1SBingbu Cao 		return ret;
63224e9edc1SBingbu Cao 
63324e9edc1SBingbu Cao 	ret = ov5675_write_reg(ov5675, OV5675_REG_GROUP_ACCESS,
63424e9edc1SBingbu Cao 			       OV5675_REG_VALUE_08BIT,
63524e9edc1SBingbu Cao 			       OV5675_GROUP_HOLD_END);
63624e9edc1SBingbu Cao 	if (ret)
63724e9edc1SBingbu Cao 		return ret;
63824e9edc1SBingbu Cao 
63924e9edc1SBingbu Cao 	ret = ov5675_write_reg(ov5675, OV5675_REG_GROUP_ACCESS,
64024e9edc1SBingbu Cao 			       OV5675_REG_VALUE_08BIT,
64124e9edc1SBingbu Cao 			       OV5675_GROUP_HOLD_LAUNCH);
64224e9edc1SBingbu Cao 	return ret;
643bf27502bSShawn Tu }
644bf27502bSShawn Tu 
ov5675_test_pattern(struct ov5675 * ov5675,u32 pattern)645bf27502bSShawn Tu static int ov5675_test_pattern(struct ov5675 *ov5675, u32 pattern)
646bf27502bSShawn Tu {
647bf27502bSShawn Tu 	if (pattern)
648bf27502bSShawn Tu 		pattern = (pattern - 1) << OV5675_TEST_PATTERN_BAR_SHIFT |
649bf27502bSShawn Tu 			  OV5675_TEST_PATTERN_ENABLE;
650bf27502bSShawn Tu 
651bf27502bSShawn Tu 	return ov5675_write_reg(ov5675, OV5675_REG_TEST_PATTERN,
652bf27502bSShawn Tu 				OV5675_REG_VALUE_08BIT, pattern);
653bf27502bSShawn Tu }
654bf27502bSShawn Tu 
655e8882e1bSShawn Tu /*
656e8882e1bSShawn Tu  * OV5675 supports keeping the pixel order by mirror and flip function
657e8882e1bSShawn Tu  * The Bayer order isn't affected by the flip controls
658e8882e1bSShawn Tu  */
ov5675_set_ctrl_hflip(struct ov5675 * ov5675,u32 ctrl_val)659e8882e1bSShawn Tu static int ov5675_set_ctrl_hflip(struct ov5675 *ov5675, u32 ctrl_val)
660e8882e1bSShawn Tu {
661e8882e1bSShawn Tu 	int ret;
662e8882e1bSShawn Tu 	u32 val;
663e8882e1bSShawn Tu 
664e8882e1bSShawn Tu 	ret = ov5675_read_reg(ov5675, OV5675_REG_FORMAT1,
665e8882e1bSShawn Tu 			      OV5675_REG_VALUE_08BIT, &val);
666e8882e1bSShawn Tu 	if (ret)
667e8882e1bSShawn Tu 		return ret;
668e8882e1bSShawn Tu 
669e8882e1bSShawn Tu 	return ov5675_write_reg(ov5675, OV5675_REG_FORMAT1,
670e8882e1bSShawn Tu 				OV5675_REG_VALUE_08BIT,
6716f862f84SShawn Tu 				ctrl_val ? val & ~BIT(3) : val | BIT(3));
672e8882e1bSShawn Tu }
673e8882e1bSShawn Tu 
ov5675_set_ctrl_vflip(struct ov5675 * ov5675,u8 ctrl_val)674e8882e1bSShawn Tu static int ov5675_set_ctrl_vflip(struct ov5675 *ov5675, u8 ctrl_val)
675e8882e1bSShawn Tu {
676e8882e1bSShawn Tu 	int ret;
677e8882e1bSShawn Tu 	u32 val;
678e8882e1bSShawn Tu 
679e8882e1bSShawn Tu 	ret = ov5675_read_reg(ov5675, OV5675_REG_FORMAT1,
680e8882e1bSShawn Tu 			      OV5675_REG_VALUE_08BIT, &val);
681e8882e1bSShawn Tu 	if (ret)
682e8882e1bSShawn Tu 		return ret;
683e8882e1bSShawn Tu 
684e8882e1bSShawn Tu 	ret = ov5675_write_reg(ov5675, OV5675_REG_FORMAT1,
685e8882e1bSShawn Tu 			       OV5675_REG_VALUE_08BIT,
6866f862f84SShawn Tu 			       ctrl_val ? val | BIT(4) | BIT(5)  : val & ~BIT(4) & ~BIT(5));
687e8882e1bSShawn Tu 
688e8882e1bSShawn Tu 	if (ret)
689e8882e1bSShawn Tu 		return ret;
690e8882e1bSShawn Tu 
691e8882e1bSShawn Tu 	ret = ov5675_read_reg(ov5675, OV5675_REG_FORMAT2,
692e8882e1bSShawn Tu 			      OV5675_REG_VALUE_08BIT, &val);
693e8882e1bSShawn Tu 
694e8882e1bSShawn Tu 	if (ret)
695e8882e1bSShawn Tu 		return ret;
696e8882e1bSShawn Tu 
697e8882e1bSShawn Tu 	return ov5675_write_reg(ov5675, OV5675_REG_FORMAT2,
698e8882e1bSShawn Tu 				OV5675_REG_VALUE_08BIT,
6996f862f84SShawn Tu 				ctrl_val ? val | BIT(1) : val & ~BIT(1));
700e8882e1bSShawn Tu }
701e8882e1bSShawn Tu 
ov5675_set_ctrl(struct v4l2_ctrl * ctrl)702bf27502bSShawn Tu static int ov5675_set_ctrl(struct v4l2_ctrl *ctrl)
703bf27502bSShawn Tu {
704bf27502bSShawn Tu 	struct ov5675 *ov5675 = container_of(ctrl->handler,
705bf27502bSShawn Tu 					     struct ov5675, ctrl_handler);
706bf27502bSShawn Tu 	struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd);
707bf27502bSShawn Tu 	s64 exposure_max;
708bf27502bSShawn Tu 	int ret = 0;
709bf27502bSShawn Tu 
710bf27502bSShawn Tu 	/* Propagate change of current control to all related controls */
711bf27502bSShawn Tu 	if (ctrl->id == V4L2_CID_VBLANK) {
712bf27502bSShawn Tu 		/* Update max exposure while meeting expected vblanking */
713ab3d4b41SBingbu Cao 		exposure_max = ov5675->cur_mode->height + ctrl->val -
714ab3d4b41SBingbu Cao 			OV5675_EXPOSURE_MAX_MARGIN;
715bf27502bSShawn Tu 		__v4l2_ctrl_modify_range(ov5675->exposure,
716bf27502bSShawn Tu 					 ov5675->exposure->minimum,
717bf27502bSShawn Tu 					 exposure_max, ov5675->exposure->step,
718bf27502bSShawn Tu 					 exposure_max);
719bf27502bSShawn Tu 	}
720bf27502bSShawn Tu 
721bf27502bSShawn Tu 	/* V4L2 controls values will be applied only when power is already up */
722bf27502bSShawn Tu 	if (!pm_runtime_get_if_in_use(&client->dev))
723bf27502bSShawn Tu 		return 0;
724bf27502bSShawn Tu 
725bf27502bSShawn Tu 	switch (ctrl->id) {
726bf27502bSShawn Tu 	case V4L2_CID_ANALOGUE_GAIN:
727bf27502bSShawn Tu 		ret = ov5675_write_reg(ov5675, OV5675_REG_ANALOG_GAIN,
728bf27502bSShawn Tu 				       OV5675_REG_VALUE_16BIT, ctrl->val);
729bf27502bSShawn Tu 		break;
730bf27502bSShawn Tu 
731bf27502bSShawn Tu 	case V4L2_CID_DIGITAL_GAIN:
732bf27502bSShawn Tu 		ret = ov5675_update_digital_gain(ov5675, ctrl->val);
733bf27502bSShawn Tu 		break;
734bf27502bSShawn Tu 
735bf27502bSShawn Tu 	case V4L2_CID_EXPOSURE:
736ab3d4b41SBingbu Cao 		/* 4 least significant bits of expsoure are fractional part
737ab3d4b41SBingbu Cao 		 * val = val << 4
738ab3d4b41SBingbu Cao 		 * for ov5675, the unit of exposure is differnt from other
739ab3d4b41SBingbu Cao 		 * OmniVision sensors, its exposure value is twice of the
740ab3d4b41SBingbu Cao 		 * register value, the exposure should be divided by 2 before
741ab3d4b41SBingbu Cao 		 * set register, e.g. val << 3.
742ab3d4b41SBingbu Cao 		 */
743bf27502bSShawn Tu 		ret = ov5675_write_reg(ov5675, OV5675_REG_EXPOSURE,
744bf27502bSShawn Tu 				       OV5675_REG_VALUE_24BIT, ctrl->val << 3);
745bf27502bSShawn Tu 		break;
746bf27502bSShawn Tu 
747bf27502bSShawn Tu 	case V4L2_CID_VBLANK:
748bf27502bSShawn Tu 		ret = ov5675_write_reg(ov5675, OV5675_REG_VTS,
749bf27502bSShawn Tu 				       OV5675_REG_VALUE_16BIT,
750bf27502bSShawn Tu 				       ov5675->cur_mode->height + ctrl->val +
751bf27502bSShawn Tu 				       10);
752bf27502bSShawn Tu 		break;
753bf27502bSShawn Tu 
754bf27502bSShawn Tu 	case V4L2_CID_TEST_PATTERN:
755bf27502bSShawn Tu 		ret = ov5675_test_pattern(ov5675, ctrl->val);
756bf27502bSShawn Tu 		break;
757bf27502bSShawn Tu 
758e8882e1bSShawn Tu 	case V4L2_CID_HFLIP:
759e8882e1bSShawn Tu 		ov5675_set_ctrl_hflip(ov5675, ctrl->val);
760e8882e1bSShawn Tu 		break;
761e8882e1bSShawn Tu 
762e8882e1bSShawn Tu 	case V4L2_CID_VFLIP:
763e8882e1bSShawn Tu 		ov5675_set_ctrl_vflip(ov5675, ctrl->val);
764e8882e1bSShawn Tu 		break;
765e8882e1bSShawn Tu 
766bf27502bSShawn Tu 	default:
767bf27502bSShawn Tu 		ret = -EINVAL;
768bf27502bSShawn Tu 		break;
769bf27502bSShawn Tu 	}
770bf27502bSShawn Tu 
771bf27502bSShawn Tu 	pm_runtime_put(&client->dev);
772bf27502bSShawn Tu 
773bf27502bSShawn Tu 	return ret;
774bf27502bSShawn Tu }
775bf27502bSShawn Tu 
776bf27502bSShawn Tu static const struct v4l2_ctrl_ops ov5675_ctrl_ops = {
777bf27502bSShawn Tu 	.s_ctrl = ov5675_set_ctrl,
778bf27502bSShawn Tu };
779bf27502bSShawn Tu 
ov5675_init_controls(struct ov5675 * ov5675)780bf27502bSShawn Tu static int ov5675_init_controls(struct ov5675 *ov5675)
781bf27502bSShawn Tu {
782c8aa2111SQuentin Schulz 	struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd);
783c8aa2111SQuentin Schulz 	struct v4l2_fwnode_device_properties props;
784bf27502bSShawn Tu 	struct v4l2_ctrl_handler *ctrl_hdlr;
785bf27502bSShawn Tu 	s64 exposure_max, h_blank;
786bf27502bSShawn Tu 	int ret;
787bf27502bSShawn Tu 
788bf27502bSShawn Tu 	ctrl_hdlr = &ov5675->ctrl_handler;
789c8aa2111SQuentin Schulz 	ret = v4l2_ctrl_handler_init(ctrl_hdlr, 10);
790bf27502bSShawn Tu 	if (ret)
791bf27502bSShawn Tu 		return ret;
792bf27502bSShawn Tu 
793bf27502bSShawn Tu 	ctrl_hdlr->lock = &ov5675->mutex;
794bf27502bSShawn Tu 	ov5675->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &ov5675_ctrl_ops,
795bf27502bSShawn Tu 					   V4L2_CID_LINK_FREQ,
796bf27502bSShawn Tu 					   ARRAY_SIZE(link_freq_menu_items) - 1,
797bf27502bSShawn Tu 					   0, link_freq_menu_items);
798bf27502bSShawn Tu 	if (ov5675->link_freq)
799bf27502bSShawn Tu 		ov5675->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
800bf27502bSShawn Tu 
801bf27502bSShawn Tu 	ov5675->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &ov5675_ctrl_ops,
802bf27502bSShawn Tu 				       V4L2_CID_PIXEL_RATE, 0,
803bf27502bSShawn Tu 				       to_pixel_rate(OV5675_LINK_FREQ_900MBPS),
804bf27502bSShawn Tu 				       1,
805bf27502bSShawn Tu 				       to_pixel_rate(OV5675_LINK_FREQ_900MBPS));
806bf27502bSShawn Tu 	ov5675->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov5675_ctrl_ops,
807bf27502bSShawn Tu 			  V4L2_CID_VBLANK,
808bf27502bSShawn Tu 			  ov5675->cur_mode->vts_min - ov5675->cur_mode->height,
809bf27502bSShawn Tu 			  OV5675_VTS_MAX - ov5675->cur_mode->height, 1,
810bf27502bSShawn Tu 			  ov5675->cur_mode->vts_def - ov5675->cur_mode->height);
811bf27502bSShawn Tu 	h_blank = to_pixels_per_line(ov5675->cur_mode->hts,
812bf27502bSShawn Tu 		  ov5675->cur_mode->link_freq_index) - ov5675->cur_mode->width;
813bf27502bSShawn Tu 	ov5675->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov5675_ctrl_ops,
814bf27502bSShawn Tu 					   V4L2_CID_HBLANK, h_blank, h_blank, 1,
815bf27502bSShawn Tu 					   h_blank);
816bf27502bSShawn Tu 	if (ov5675->hblank)
817bf27502bSShawn Tu 		ov5675->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
818bf27502bSShawn Tu 
819bf27502bSShawn Tu 	v4l2_ctrl_new_std(ctrl_hdlr, &ov5675_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
820bf27502bSShawn Tu 			  OV5675_ANAL_GAIN_MIN, OV5675_ANAL_GAIN_MAX,
821bf27502bSShawn Tu 			  OV5675_ANAL_GAIN_STEP, OV5675_ANAL_GAIN_MIN);
822bf27502bSShawn Tu 	v4l2_ctrl_new_std(ctrl_hdlr, &ov5675_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
823bf27502bSShawn Tu 			  OV5675_DGTL_GAIN_MIN, OV5675_DGTL_GAIN_MAX,
824bf27502bSShawn Tu 			  OV5675_DGTL_GAIN_STEP, OV5675_DGTL_GAIN_DEFAULT);
825ab3d4b41SBingbu Cao 	exposure_max = (ov5675->cur_mode->vts_def - OV5675_EXPOSURE_MAX_MARGIN);
826bf27502bSShawn Tu 	ov5675->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &ov5675_ctrl_ops,
827bf27502bSShawn Tu 					     V4L2_CID_EXPOSURE,
828bf27502bSShawn Tu 					     OV5675_EXPOSURE_MIN, exposure_max,
829bf27502bSShawn Tu 					     OV5675_EXPOSURE_STEP,
830bf27502bSShawn Tu 					     exposure_max);
831bf27502bSShawn Tu 	v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &ov5675_ctrl_ops,
832bf27502bSShawn Tu 				     V4L2_CID_TEST_PATTERN,
833bf27502bSShawn Tu 				     ARRAY_SIZE(ov5675_test_pattern_menu) - 1,
834bf27502bSShawn Tu 				     0, 0, ov5675_test_pattern_menu);
835e8882e1bSShawn Tu 	v4l2_ctrl_new_std(ctrl_hdlr, &ov5675_ctrl_ops,
836e8882e1bSShawn Tu 			  V4L2_CID_HFLIP, 0, 1, 1, 0);
837e8882e1bSShawn Tu 	v4l2_ctrl_new_std(ctrl_hdlr, &ov5675_ctrl_ops,
838e8882e1bSShawn Tu 			  V4L2_CID_VFLIP, 0, 1, 1, 0);
839e8882e1bSShawn Tu 
840dd74ed6cSShang XiaoJing 	if (ctrl_hdlr->error) {
841dd74ed6cSShang XiaoJing 		v4l2_ctrl_handler_free(ctrl_hdlr);
842bf27502bSShawn Tu 		return ctrl_hdlr->error;
843dd74ed6cSShang XiaoJing 	}
844bf27502bSShawn Tu 
845c8aa2111SQuentin Schulz 	ret = v4l2_fwnode_device_parse(&client->dev, &props);
846c8aa2111SQuentin Schulz 	if (ret)
847c8aa2111SQuentin Schulz 		goto error;
848c8aa2111SQuentin Schulz 
849c8aa2111SQuentin Schulz 	ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &ov5675_ctrl_ops,
850c8aa2111SQuentin Schulz 					      &props);
851c8aa2111SQuentin Schulz 	if (ret)
852c8aa2111SQuentin Schulz 		goto error;
853c8aa2111SQuentin Schulz 
854bf27502bSShawn Tu 	ov5675->sd.ctrl_handler = ctrl_hdlr;
855bf27502bSShawn Tu 
856bf27502bSShawn Tu 	return 0;
857c8aa2111SQuentin Schulz 
858c8aa2111SQuentin Schulz error:
859c8aa2111SQuentin Schulz 	v4l2_ctrl_handler_free(ctrl_hdlr);
860c8aa2111SQuentin Schulz 
861c8aa2111SQuentin Schulz 	return ret;
862bf27502bSShawn Tu }
863bf27502bSShawn Tu 
ov5675_update_pad_format(const struct ov5675_mode * mode,struct v4l2_mbus_framefmt * fmt)864bf27502bSShawn Tu static void ov5675_update_pad_format(const struct ov5675_mode *mode,
865bf27502bSShawn Tu 				     struct v4l2_mbus_framefmt *fmt)
866bf27502bSShawn Tu {
867bf27502bSShawn Tu 	fmt->width = mode->width;
868bf27502bSShawn Tu 	fmt->height = mode->height;
869bf27502bSShawn Tu 	fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
870bf27502bSShawn Tu 	fmt->field = V4L2_FIELD_NONE;
871bf27502bSShawn Tu }
872bf27502bSShawn Tu 
ov5675_identify_module(struct ov5675 * ov5675)8735525fd86SBingbu Cao static int ov5675_identify_module(struct ov5675 *ov5675)
8745525fd86SBingbu Cao {
8755525fd86SBingbu Cao 	struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd);
8765525fd86SBingbu Cao 	int ret;
8775525fd86SBingbu Cao 	u32 val;
8785525fd86SBingbu Cao 
8795525fd86SBingbu Cao 	if (ov5675->identified)
8805525fd86SBingbu Cao 		return 0;
8815525fd86SBingbu Cao 
8825525fd86SBingbu Cao 	ret = ov5675_read_reg(ov5675, OV5675_REG_CHIP_ID,
8835525fd86SBingbu Cao 			      OV5675_REG_VALUE_24BIT, &val);
8845525fd86SBingbu Cao 	if (ret)
8855525fd86SBingbu Cao 		return ret;
8865525fd86SBingbu Cao 
8875525fd86SBingbu Cao 	if (val != OV5675_CHIP_ID) {
8885525fd86SBingbu Cao 		dev_err(&client->dev, "chip id mismatch: %x!=%x",
8895525fd86SBingbu Cao 			OV5675_CHIP_ID, val);
8905525fd86SBingbu Cao 		return -ENXIO;
8915525fd86SBingbu Cao 	}
8925525fd86SBingbu Cao 
8935525fd86SBingbu Cao 	ov5675->identified = true;
8945525fd86SBingbu Cao 
8955525fd86SBingbu Cao 	return 0;
8965525fd86SBingbu Cao }
8975525fd86SBingbu Cao 
ov5675_start_streaming(struct ov5675 * ov5675)898bf27502bSShawn Tu static int ov5675_start_streaming(struct ov5675 *ov5675)
899bf27502bSShawn Tu {
900bf27502bSShawn Tu 	struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd);
901bf27502bSShawn Tu 	const struct ov5675_reg_list *reg_list;
902bf27502bSShawn Tu 	int link_freq_index, ret;
903bf27502bSShawn Tu 
9045525fd86SBingbu Cao 	ret = ov5675_identify_module(ov5675);
9055525fd86SBingbu Cao 	if (ret)
9065525fd86SBingbu Cao 		return ret;
9075525fd86SBingbu Cao 
908bf27502bSShawn Tu 	link_freq_index = ov5675->cur_mode->link_freq_index;
909bf27502bSShawn Tu 	reg_list = &link_freq_configs[link_freq_index].reg_list;
910bf27502bSShawn Tu 	ret = ov5675_write_reg_list(ov5675, reg_list);
911bf27502bSShawn Tu 	if (ret) {
912bf27502bSShawn Tu 		dev_err(&client->dev, "failed to set plls");
913bf27502bSShawn Tu 		return ret;
914bf27502bSShawn Tu 	}
915bf27502bSShawn Tu 
916bf27502bSShawn Tu 	reg_list = &ov5675->cur_mode->reg_list;
917bf27502bSShawn Tu 	ret = ov5675_write_reg_list(ov5675, reg_list);
918bf27502bSShawn Tu 	if (ret) {
919bf27502bSShawn Tu 		dev_err(&client->dev, "failed to set mode");
920bf27502bSShawn Tu 		return ret;
921bf27502bSShawn Tu 	}
922bf27502bSShawn Tu 
923bf27502bSShawn Tu 	ret = __v4l2_ctrl_handler_setup(ov5675->sd.ctrl_handler);
924bf27502bSShawn Tu 	if (ret)
925bf27502bSShawn Tu 		return ret;
926bf27502bSShawn Tu 
927bf27502bSShawn Tu 	ret = ov5675_write_reg(ov5675, OV5675_REG_MODE_SELECT,
928bf27502bSShawn Tu 			       OV5675_REG_VALUE_08BIT, OV5675_MODE_STREAMING);
929bf27502bSShawn Tu 	if (ret) {
930bf27502bSShawn Tu 		dev_err(&client->dev, "failed to set stream");
931bf27502bSShawn Tu 		return ret;
932bf27502bSShawn Tu 	}
933bf27502bSShawn Tu 
934bf27502bSShawn Tu 	return 0;
935bf27502bSShawn Tu }
936bf27502bSShawn Tu 
ov5675_stop_streaming(struct ov5675 * ov5675)937bf27502bSShawn Tu static void ov5675_stop_streaming(struct ov5675 *ov5675)
938bf27502bSShawn Tu {
939bf27502bSShawn Tu 	struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd);
940bf27502bSShawn Tu 
941bf27502bSShawn Tu 	if (ov5675_write_reg(ov5675, OV5675_REG_MODE_SELECT,
942bf27502bSShawn Tu 			     OV5675_REG_VALUE_08BIT, OV5675_MODE_STANDBY))
943bf27502bSShawn Tu 		dev_err(&client->dev, "failed to set stream");
944bf27502bSShawn Tu }
945bf27502bSShawn Tu 
ov5675_set_stream(struct v4l2_subdev * sd,int enable)946bf27502bSShawn Tu static int ov5675_set_stream(struct v4l2_subdev *sd, int enable)
947bf27502bSShawn Tu {
948bf27502bSShawn Tu 	struct ov5675 *ov5675 = to_ov5675(sd);
949bf27502bSShawn Tu 	struct i2c_client *client = v4l2_get_subdevdata(sd);
950bf27502bSShawn Tu 	int ret = 0;
951bf27502bSShawn Tu 
952bf27502bSShawn Tu 	if (ov5675->streaming == enable)
953bf27502bSShawn Tu 		return 0;
954bf27502bSShawn Tu 
955bf27502bSShawn Tu 	mutex_lock(&ov5675->mutex);
956bf27502bSShawn Tu 	if (enable) {
957f236bb24SMauro Carvalho Chehab 		ret = pm_runtime_resume_and_get(&client->dev);
958bf27502bSShawn Tu 		if (ret < 0) {
959bf27502bSShawn Tu 			mutex_unlock(&ov5675->mutex);
960bf27502bSShawn Tu 			return ret;
961bf27502bSShawn Tu 		}
962bf27502bSShawn Tu 
963bf27502bSShawn Tu 		ret = ov5675_start_streaming(ov5675);
964bf27502bSShawn Tu 		if (ret) {
965bf27502bSShawn Tu 			enable = 0;
966bf27502bSShawn Tu 			ov5675_stop_streaming(ov5675);
967bf27502bSShawn Tu 			pm_runtime_put(&client->dev);
968bf27502bSShawn Tu 		}
969bf27502bSShawn Tu 	} else {
970bf27502bSShawn Tu 		ov5675_stop_streaming(ov5675);
971bf27502bSShawn Tu 		pm_runtime_put(&client->dev);
972bf27502bSShawn Tu 	}
973bf27502bSShawn Tu 
974bf27502bSShawn Tu 	ov5675->streaming = enable;
975bf27502bSShawn Tu 	mutex_unlock(&ov5675->mutex);
976bf27502bSShawn Tu 
977bf27502bSShawn Tu 	return ret;
978bf27502bSShawn Tu }
979bf27502bSShawn Tu 
ov5675_power_off(struct device * dev)98049d9ad71SQuentin Schulz static int ov5675_power_off(struct device *dev)
98149d9ad71SQuentin Schulz {
98249d9ad71SQuentin Schulz 	/* 512 xvclk cycles after the last SCCB transation or MIPI frame end */
98349d9ad71SQuentin Schulz 	u32 delay_us = DIV_ROUND_UP(512, OV5675_XVCLK_19_2 / 1000 / 1000);
98449d9ad71SQuentin Schulz 	struct v4l2_subdev *sd = dev_get_drvdata(dev);
98549d9ad71SQuentin Schulz 	struct ov5675 *ov5675 = to_ov5675(sd);
98649d9ad71SQuentin Schulz 
98749d9ad71SQuentin Schulz 	usleep_range(delay_us, delay_us * 2);
98849d9ad71SQuentin Schulz 
98949d9ad71SQuentin Schulz 	clk_disable_unprepare(ov5675->xvclk);
99049d9ad71SQuentin Schulz 	gpiod_set_value_cansleep(ov5675->reset_gpio, 1);
99149d9ad71SQuentin Schulz 	regulator_bulk_disable(OV5675_NUM_SUPPLIES, ov5675->supplies);
99249d9ad71SQuentin Schulz 
99349d9ad71SQuentin Schulz 	return 0;
99449d9ad71SQuentin Schulz }
99549d9ad71SQuentin Schulz 
ov5675_power_on(struct device * dev)99649d9ad71SQuentin Schulz static int ov5675_power_on(struct device *dev)
99749d9ad71SQuentin Schulz {
99849d9ad71SQuentin Schulz 	u32 delay_us = DIV_ROUND_UP(8192, OV5675_XVCLK_19_2 / 1000 / 1000);
99949d9ad71SQuentin Schulz 	struct v4l2_subdev *sd = dev_get_drvdata(dev);
100049d9ad71SQuentin Schulz 	struct ov5675 *ov5675 = to_ov5675(sd);
100149d9ad71SQuentin Schulz 	int ret;
100249d9ad71SQuentin Schulz 
100349d9ad71SQuentin Schulz 	ret = clk_prepare_enable(ov5675->xvclk);
100449d9ad71SQuentin Schulz 	if (ret < 0) {
100549d9ad71SQuentin Schulz 		dev_err(dev, "failed to enable xvclk: %d\n", ret);
100649d9ad71SQuentin Schulz 		return ret;
100749d9ad71SQuentin Schulz 	}
100849d9ad71SQuentin Schulz 
100949d9ad71SQuentin Schulz 	gpiod_set_value_cansleep(ov5675->reset_gpio, 1);
101049d9ad71SQuentin Schulz 
101149d9ad71SQuentin Schulz 	ret = regulator_bulk_enable(OV5675_NUM_SUPPLIES, ov5675->supplies);
101249d9ad71SQuentin Schulz 	if (ret) {
101349d9ad71SQuentin Schulz 		clk_disable_unprepare(ov5675->xvclk);
101449d9ad71SQuentin Schulz 		return ret;
101549d9ad71SQuentin Schulz 	}
101649d9ad71SQuentin Schulz 
101749d9ad71SQuentin Schulz 	/* Reset pulse should be at least 2ms and reset gpio released only once
101849d9ad71SQuentin Schulz 	 * regulators are stable.
101949d9ad71SQuentin Schulz 	 */
102049d9ad71SQuentin Schulz 	usleep_range(2000, 2200);
102149d9ad71SQuentin Schulz 
102249d9ad71SQuentin Schulz 	gpiod_set_value_cansleep(ov5675->reset_gpio, 0);
102349d9ad71SQuentin Schulz 
102449d9ad71SQuentin Schulz 	/* 8192 xvclk cycles prior to the first SCCB transation */
102549d9ad71SQuentin Schulz 	usleep_range(delay_us, delay_us * 2);
102649d9ad71SQuentin Schulz 
102749d9ad71SQuentin Schulz 	return 0;
102849d9ad71SQuentin Schulz }
102949d9ad71SQuentin Schulz 
ov5675_suspend(struct device * dev)1030bf27502bSShawn Tu static int __maybe_unused ov5675_suspend(struct device *dev)
1031bf27502bSShawn Tu {
10321a747125SKrzysztof Kozlowski 	struct v4l2_subdev *sd = dev_get_drvdata(dev);
1033bf27502bSShawn Tu 	struct ov5675 *ov5675 = to_ov5675(sd);
1034bf27502bSShawn Tu 
1035bf27502bSShawn Tu 	mutex_lock(&ov5675->mutex);
1036bf27502bSShawn Tu 	if (ov5675->streaming)
1037bf27502bSShawn Tu 		ov5675_stop_streaming(ov5675);
1038bf27502bSShawn Tu 
1039bf27502bSShawn Tu 	mutex_unlock(&ov5675->mutex);
1040bf27502bSShawn Tu 
1041bf27502bSShawn Tu 	return 0;
1042bf27502bSShawn Tu }
1043bf27502bSShawn Tu 
ov5675_resume(struct device * dev)1044bf27502bSShawn Tu static int __maybe_unused ov5675_resume(struct device *dev)
1045bf27502bSShawn Tu {
10461a747125SKrzysztof Kozlowski 	struct v4l2_subdev *sd = dev_get_drvdata(dev);
1047bf27502bSShawn Tu 	struct ov5675 *ov5675 = to_ov5675(sd);
1048bf27502bSShawn Tu 	int ret;
1049bf27502bSShawn Tu 
1050bf27502bSShawn Tu 	mutex_lock(&ov5675->mutex);
1051bf27502bSShawn Tu 	if (ov5675->streaming) {
1052bf27502bSShawn Tu 		ret = ov5675_start_streaming(ov5675);
1053bf27502bSShawn Tu 		if (ret) {
1054bf27502bSShawn Tu 			ov5675->streaming = false;
1055bf27502bSShawn Tu 			ov5675_stop_streaming(ov5675);
1056bf27502bSShawn Tu 			mutex_unlock(&ov5675->mutex);
1057bf27502bSShawn Tu 			return ret;
1058bf27502bSShawn Tu 		}
1059bf27502bSShawn Tu 	}
1060bf27502bSShawn Tu 
1061bf27502bSShawn Tu 	mutex_unlock(&ov5675->mutex);
1062bf27502bSShawn Tu 
1063bf27502bSShawn Tu 	return 0;
1064bf27502bSShawn Tu }
1065bf27502bSShawn Tu 
ov5675_set_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)1066bf27502bSShawn Tu static int ov5675_set_format(struct v4l2_subdev *sd,
10670d346d2aSTomi Valkeinen 			     struct v4l2_subdev_state *sd_state,
1068bf27502bSShawn Tu 			     struct v4l2_subdev_format *fmt)
1069bf27502bSShawn Tu {
1070bf27502bSShawn Tu 	struct ov5675 *ov5675 = to_ov5675(sd);
1071bf27502bSShawn Tu 	const struct ov5675_mode *mode;
1072bf27502bSShawn Tu 	s32 vblank_def, h_blank;
1073bf27502bSShawn Tu 
1074bf27502bSShawn Tu 	mode = v4l2_find_nearest_size(supported_modes,
1075bf27502bSShawn Tu 				      ARRAY_SIZE(supported_modes), width,
1076bf27502bSShawn Tu 				      height, fmt->format.width,
1077bf27502bSShawn Tu 				      fmt->format.height);
1078bf27502bSShawn Tu 
1079bf27502bSShawn Tu 	mutex_lock(&ov5675->mutex);
1080bf27502bSShawn Tu 	ov5675_update_pad_format(mode, &fmt->format);
1081bf27502bSShawn Tu 	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
10820d346d2aSTomi Valkeinen 		*v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format;
1083bf27502bSShawn Tu 	} else {
1084bf27502bSShawn Tu 		ov5675->cur_mode = mode;
1085bf27502bSShawn Tu 		__v4l2_ctrl_s_ctrl(ov5675->link_freq, mode->link_freq_index);
1086bf27502bSShawn Tu 		__v4l2_ctrl_s_ctrl_int64(ov5675->pixel_rate,
1087bf27502bSShawn Tu 					 to_pixel_rate(mode->link_freq_index));
1088bf27502bSShawn Tu 
1089bf27502bSShawn Tu 		/* Update limits and set FPS to default */
1090bf27502bSShawn Tu 		vblank_def = mode->vts_def - mode->height;
1091bf27502bSShawn Tu 		__v4l2_ctrl_modify_range(ov5675->vblank,
1092bf27502bSShawn Tu 					 mode->vts_min - mode->height,
1093bf27502bSShawn Tu 					 OV5675_VTS_MAX - mode->height, 1,
1094bf27502bSShawn Tu 					 vblank_def);
1095bf27502bSShawn Tu 		__v4l2_ctrl_s_ctrl(ov5675->vblank, vblank_def);
1096bf27502bSShawn Tu 		h_blank = to_pixels_per_line(mode->hts, mode->link_freq_index) -
1097bf27502bSShawn Tu 			  mode->width;
1098bf27502bSShawn Tu 		__v4l2_ctrl_modify_range(ov5675->hblank, h_blank, h_blank, 1,
1099bf27502bSShawn Tu 					 h_blank);
1100bf27502bSShawn Tu 	}
1101bf27502bSShawn Tu 
1102bf27502bSShawn Tu 	mutex_unlock(&ov5675->mutex);
1103bf27502bSShawn Tu 
1104bf27502bSShawn Tu 	return 0;
1105bf27502bSShawn Tu }
1106bf27502bSShawn Tu 
ov5675_get_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)1107bf27502bSShawn Tu static int ov5675_get_format(struct v4l2_subdev *sd,
11080d346d2aSTomi Valkeinen 			     struct v4l2_subdev_state *sd_state,
1109bf27502bSShawn Tu 			     struct v4l2_subdev_format *fmt)
1110bf27502bSShawn Tu {
1111bf27502bSShawn Tu 	struct ov5675 *ov5675 = to_ov5675(sd);
1112bf27502bSShawn Tu 
1113bf27502bSShawn Tu 	mutex_lock(&ov5675->mutex);
1114bf27502bSShawn Tu 	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
11150d346d2aSTomi Valkeinen 		fmt->format = *v4l2_subdev_get_try_format(&ov5675->sd,
11160d346d2aSTomi Valkeinen 							  sd_state,
1117bf27502bSShawn Tu 							  fmt->pad);
1118bf27502bSShawn Tu 	else
1119bf27502bSShawn Tu 		ov5675_update_pad_format(ov5675->cur_mode, &fmt->format);
1120bf27502bSShawn Tu 
1121bf27502bSShawn Tu 	mutex_unlock(&ov5675->mutex);
1122bf27502bSShawn Tu 
1123bf27502bSShawn Tu 	return 0;
1124bf27502bSShawn Tu }
1125bf27502bSShawn Tu 
ov5675_get_selection(struct v4l2_subdev * sd,struct v4l2_subdev_state * state,struct v4l2_subdev_selection * sel)1126221827eeSQuentin Schulz static int ov5675_get_selection(struct v4l2_subdev *sd,
1127221827eeSQuentin Schulz 				struct v4l2_subdev_state *state,
1128221827eeSQuentin Schulz 				struct v4l2_subdev_selection *sel)
1129221827eeSQuentin Schulz {
1130221827eeSQuentin Schulz 	if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
1131221827eeSQuentin Schulz 		return -EINVAL;
1132221827eeSQuentin Schulz 
1133221827eeSQuentin Schulz 	switch (sel->target) {
1134221827eeSQuentin Schulz 	case V4L2_SEL_TGT_CROP_BOUNDS:
1135221827eeSQuentin Schulz 		sel->r.top = 0;
1136221827eeSQuentin Schulz 		sel->r.left = 0;
1137221827eeSQuentin Schulz 		sel->r.width = 2624;
1138221827eeSQuentin Schulz 		sel->r.height = 2000;
1139221827eeSQuentin Schulz 		return 0;
1140221827eeSQuentin Schulz 	case V4L2_SEL_TGT_CROP:
1141221827eeSQuentin Schulz 	case V4L2_SEL_TGT_CROP_DEFAULT:
1142221827eeSQuentin Schulz 		sel->r.top = 16;
1143221827eeSQuentin Schulz 		sel->r.left = 16;
1144221827eeSQuentin Schulz 		sel->r.width = 2592;
1145221827eeSQuentin Schulz 		sel->r.height = 1944;
1146221827eeSQuentin Schulz 		return 0;
1147221827eeSQuentin Schulz 	}
1148221827eeSQuentin Schulz 	return -EINVAL;
1149221827eeSQuentin Schulz }
1150221827eeSQuentin Schulz 
ov5675_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_mbus_code_enum * code)1151bf27502bSShawn Tu static int ov5675_enum_mbus_code(struct v4l2_subdev *sd,
11520d346d2aSTomi Valkeinen 				 struct v4l2_subdev_state *sd_state,
1153bf27502bSShawn Tu 				 struct v4l2_subdev_mbus_code_enum *code)
1154bf27502bSShawn Tu {
1155bf27502bSShawn Tu 	if (code->index > 0)
1156bf27502bSShawn Tu 		return -EINVAL;
1157bf27502bSShawn Tu 
1158bf27502bSShawn Tu 	code->code = MEDIA_BUS_FMT_SGRBG10_1X10;
1159bf27502bSShawn Tu 
1160bf27502bSShawn Tu 	return 0;
1161bf27502bSShawn Tu }
1162bf27502bSShawn Tu 
ov5675_enum_frame_size(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_frame_size_enum * fse)1163bf27502bSShawn Tu static int ov5675_enum_frame_size(struct v4l2_subdev *sd,
11640d346d2aSTomi Valkeinen 				  struct v4l2_subdev_state *sd_state,
1165bf27502bSShawn Tu 				  struct v4l2_subdev_frame_size_enum *fse)
1166bf27502bSShawn Tu {
1167bf27502bSShawn Tu 	if (fse->index >= ARRAY_SIZE(supported_modes))
1168bf27502bSShawn Tu 		return -EINVAL;
1169bf27502bSShawn Tu 
1170bf27502bSShawn Tu 	if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10)
1171bf27502bSShawn Tu 		return -EINVAL;
1172bf27502bSShawn Tu 
1173bf27502bSShawn Tu 	fse->min_width = supported_modes[fse->index].width;
1174bf27502bSShawn Tu 	fse->max_width = fse->min_width;
1175bf27502bSShawn Tu 	fse->min_height = supported_modes[fse->index].height;
1176bf27502bSShawn Tu 	fse->max_height = fse->min_height;
1177bf27502bSShawn Tu 
1178bf27502bSShawn Tu 	return 0;
1179bf27502bSShawn Tu }
1180bf27502bSShawn Tu 
ov5675_open(struct v4l2_subdev * sd,struct v4l2_subdev_fh * fh)1181bf27502bSShawn Tu static int ov5675_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
1182bf27502bSShawn Tu {
1183bf27502bSShawn Tu 	struct ov5675 *ov5675 = to_ov5675(sd);
1184bf27502bSShawn Tu 
1185bf27502bSShawn Tu 	mutex_lock(&ov5675->mutex);
1186bf27502bSShawn Tu 	ov5675_update_pad_format(&supported_modes[0],
11870d346d2aSTomi Valkeinen 				 v4l2_subdev_get_try_format(sd, fh->state, 0));
1188bf27502bSShawn Tu 	mutex_unlock(&ov5675->mutex);
1189bf27502bSShawn Tu 
1190bf27502bSShawn Tu 	return 0;
1191bf27502bSShawn Tu }
1192bf27502bSShawn Tu 
1193bf27502bSShawn Tu static const struct v4l2_subdev_video_ops ov5675_video_ops = {
1194bf27502bSShawn Tu 	.s_stream = ov5675_set_stream,
1195bf27502bSShawn Tu };
1196bf27502bSShawn Tu 
1197bf27502bSShawn Tu static const struct v4l2_subdev_pad_ops ov5675_pad_ops = {
1198bf27502bSShawn Tu 	.set_fmt = ov5675_set_format,
1199bf27502bSShawn Tu 	.get_fmt = ov5675_get_format,
1200221827eeSQuentin Schulz 	.get_selection = ov5675_get_selection,
1201bf27502bSShawn Tu 	.enum_mbus_code = ov5675_enum_mbus_code,
1202bf27502bSShawn Tu 	.enum_frame_size = ov5675_enum_frame_size,
1203bf27502bSShawn Tu };
1204bf27502bSShawn Tu 
1205bf27502bSShawn Tu static const struct v4l2_subdev_ops ov5675_subdev_ops = {
1206bf27502bSShawn Tu 	.video = &ov5675_video_ops,
1207bf27502bSShawn Tu 	.pad = &ov5675_pad_ops,
1208bf27502bSShawn Tu };
1209bf27502bSShawn Tu 
1210bf27502bSShawn Tu static const struct media_entity_operations ov5675_subdev_entity_ops = {
1211bf27502bSShawn Tu 	.link_validate = v4l2_subdev_link_validate,
1212bf27502bSShawn Tu };
1213bf27502bSShawn Tu 
1214bf27502bSShawn Tu static const struct v4l2_subdev_internal_ops ov5675_internal_ops = {
1215bf27502bSShawn Tu 	.open = ov5675_open,
1216bf27502bSShawn Tu };
1217bf27502bSShawn Tu 
ov5675_get_hwcfg(struct ov5675 * ov5675,struct device * dev)121849d9ad71SQuentin Schulz static int ov5675_get_hwcfg(struct ov5675 *ov5675, struct device *dev)
1219bf27502bSShawn Tu {
1220bf27502bSShawn Tu 	struct fwnode_handle *ep;
1221bf27502bSShawn Tu 	struct fwnode_handle *fwnode = dev_fwnode(dev);
1222bf27502bSShawn Tu 	struct v4l2_fwnode_endpoint bus_cfg = {
1223bf27502bSShawn Tu 		.bus_type = V4L2_MBUS_CSI2_DPHY
1224bf27502bSShawn Tu 	};
122549d9ad71SQuentin Schulz 	u32 xvclk_rate;
1226bf27502bSShawn Tu 	int ret;
1227bf27502bSShawn Tu 	unsigned int i, j;
1228bf27502bSShawn Tu 
1229bf27502bSShawn Tu 	if (!fwnode)
1230bf27502bSShawn Tu 		return -ENXIO;
1231bf27502bSShawn Tu 
123249d9ad71SQuentin Schulz 	ov5675->xvclk = devm_clk_get_optional(dev, NULL);
123349d9ad71SQuentin Schulz 	if (IS_ERR(ov5675->xvclk))
123449d9ad71SQuentin Schulz 		return dev_err_probe(dev, PTR_ERR(ov5675->xvclk),
123549d9ad71SQuentin Schulz 				     "failed to get xvclk: %ld\n",
123649d9ad71SQuentin Schulz 				     PTR_ERR(ov5675->xvclk));
123749d9ad71SQuentin Schulz 
123849d9ad71SQuentin Schulz 	if (ov5675->xvclk) {
123949d9ad71SQuentin Schulz 		xvclk_rate = clk_get_rate(ov5675->xvclk);
124049d9ad71SQuentin Schulz 	} else {
124149d9ad71SQuentin Schulz 		ret = fwnode_property_read_u32(fwnode, "clock-frequency",
124249d9ad71SQuentin Schulz 					       &xvclk_rate);
1243bf27502bSShawn Tu 
1244bf27502bSShawn Tu 		if (ret) {
1245bf27502bSShawn Tu 			dev_err(dev, "can't get clock frequency");
1246bf27502bSShawn Tu 			return ret;
1247bf27502bSShawn Tu 		}
124849d9ad71SQuentin Schulz 	}
1249bf27502bSShawn Tu 
125049d9ad71SQuentin Schulz 	if (xvclk_rate != OV5675_XVCLK_19_2) {
125149d9ad71SQuentin Schulz 		dev_err(dev, "external clock rate %u is unsupported",
125249d9ad71SQuentin Schulz 			xvclk_rate);
1253bf27502bSShawn Tu 		return -EINVAL;
1254bf27502bSShawn Tu 	}
1255bf27502bSShawn Tu 
125649d9ad71SQuentin Schulz 	ov5675->reset_gpio = devm_gpiod_get_optional(dev, "reset",
125749d9ad71SQuentin Schulz 						     GPIOD_OUT_HIGH);
125849d9ad71SQuentin Schulz 	if (IS_ERR(ov5675->reset_gpio)) {
125949d9ad71SQuentin Schulz 		ret = PTR_ERR(ov5675->reset_gpio);
126049d9ad71SQuentin Schulz 		dev_err(dev, "failed to get reset-gpios: %d\n", ret);
126149d9ad71SQuentin Schulz 		return ret;
126249d9ad71SQuentin Schulz 	}
126349d9ad71SQuentin Schulz 
126449d9ad71SQuentin Schulz 	for (i = 0; i < OV5675_NUM_SUPPLIES; i++)
126549d9ad71SQuentin Schulz 		ov5675->supplies[i].supply = ov5675_supply_names[i];
126649d9ad71SQuentin Schulz 
126749d9ad71SQuentin Schulz 	ret = devm_regulator_bulk_get(dev, OV5675_NUM_SUPPLIES,
126849d9ad71SQuentin Schulz 				      ov5675->supplies);
126949d9ad71SQuentin Schulz 	if (ret)
127049d9ad71SQuentin Schulz 		return ret;
127149d9ad71SQuentin Schulz 
1272bf27502bSShawn Tu 	ep = fwnode_graph_get_next_endpoint(fwnode, NULL);
1273bf27502bSShawn Tu 	if (!ep)
1274bf27502bSShawn Tu 		return -ENXIO;
1275bf27502bSShawn Tu 
1276bf27502bSShawn Tu 	ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);
1277bf27502bSShawn Tu 	fwnode_handle_put(ep);
1278bf27502bSShawn Tu 	if (ret)
1279bf27502bSShawn Tu 		return ret;
1280bf27502bSShawn Tu 
1281bf27502bSShawn Tu 	if (bus_cfg.bus.mipi_csi2.num_data_lanes != OV5675_DATA_LANES) {
1282bf27502bSShawn Tu 		dev_err(dev, "number of CSI2 data lanes %d is not supported",
1283bf27502bSShawn Tu 			bus_cfg.bus.mipi_csi2.num_data_lanes);
1284bf27502bSShawn Tu 		ret = -EINVAL;
1285bf27502bSShawn Tu 		goto check_hwcfg_error;
1286bf27502bSShawn Tu 	}
1287bf27502bSShawn Tu 
1288bf27502bSShawn Tu 	if (!bus_cfg.nr_of_link_frequencies) {
1289bf27502bSShawn Tu 		dev_err(dev, "no link frequencies defined");
1290bf27502bSShawn Tu 		ret = -EINVAL;
1291bf27502bSShawn Tu 		goto check_hwcfg_error;
1292bf27502bSShawn Tu 	}
1293bf27502bSShawn Tu 
1294bf27502bSShawn Tu 	for (i = 0; i < ARRAY_SIZE(link_freq_menu_items); i++) {
1295bf27502bSShawn Tu 		for (j = 0; j < bus_cfg.nr_of_link_frequencies; j++) {
1296bf27502bSShawn Tu 			if (link_freq_menu_items[i] ==
1297bf27502bSShawn Tu 				bus_cfg.link_frequencies[j])
1298bf27502bSShawn Tu 				break;
1299bf27502bSShawn Tu 		}
1300bf27502bSShawn Tu 
1301bf27502bSShawn Tu 		if (j == bus_cfg.nr_of_link_frequencies) {
1302bf27502bSShawn Tu 			dev_err(dev, "no link frequency %lld supported",
1303bf27502bSShawn Tu 				link_freq_menu_items[i]);
1304bf27502bSShawn Tu 			ret = -EINVAL;
1305bf27502bSShawn Tu 			goto check_hwcfg_error;
1306bf27502bSShawn Tu 		}
1307bf27502bSShawn Tu 	}
1308bf27502bSShawn Tu 
1309bf27502bSShawn Tu check_hwcfg_error:
1310bf27502bSShawn Tu 	v4l2_fwnode_endpoint_free(&bus_cfg);
1311bf27502bSShawn Tu 
1312bf27502bSShawn Tu 	return ret;
1313bf27502bSShawn Tu }
1314bf27502bSShawn Tu 
ov5675_remove(struct i2c_client * client)1315ed5c2f5fSUwe Kleine-König static void ov5675_remove(struct i2c_client *client)
1316bf27502bSShawn Tu {
1317bf27502bSShawn Tu 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
1318bf27502bSShawn Tu 	struct ov5675 *ov5675 = to_ov5675(sd);
1319bf27502bSShawn Tu 
1320bf27502bSShawn Tu 	v4l2_async_unregister_subdev(sd);
1321bf27502bSShawn Tu 	media_entity_cleanup(&sd->entity);
1322bf27502bSShawn Tu 	v4l2_ctrl_handler_free(sd->ctrl_handler);
1323bf27502bSShawn Tu 	pm_runtime_disable(&client->dev);
1324bf27502bSShawn Tu 	mutex_destroy(&ov5675->mutex);
132549d9ad71SQuentin Schulz 
132649d9ad71SQuentin Schulz 	if (!pm_runtime_status_suspended(&client->dev))
132749d9ad71SQuentin Schulz 		ov5675_power_off(&client->dev);
132849d9ad71SQuentin Schulz 	pm_runtime_set_suspended(&client->dev);
1329bf27502bSShawn Tu }
1330bf27502bSShawn Tu 
ov5675_probe(struct i2c_client * client)1331bf27502bSShawn Tu static int ov5675_probe(struct i2c_client *client)
1332bf27502bSShawn Tu {
1333bf27502bSShawn Tu 	struct ov5675 *ov5675;
13345525fd86SBingbu Cao 	bool full_power;
1335bf27502bSShawn Tu 	int ret;
1336bf27502bSShawn Tu 
1337bf27502bSShawn Tu 	ov5675 = devm_kzalloc(&client->dev, sizeof(*ov5675), GFP_KERNEL);
1338bf27502bSShawn Tu 	if (!ov5675)
1339bf27502bSShawn Tu 		return -ENOMEM;
1340bf27502bSShawn Tu 
134149d9ad71SQuentin Schulz 	ret = ov5675_get_hwcfg(ov5675, &client->dev);
134249d9ad71SQuentin Schulz 	if (ret) {
134349d9ad71SQuentin Schulz 		dev_err(&client->dev, "failed to get HW configuration: %d",
134449d9ad71SQuentin Schulz 			ret);
134549d9ad71SQuentin Schulz 		return ret;
134649d9ad71SQuentin Schulz 	}
134749d9ad71SQuentin Schulz 
1348bf27502bSShawn Tu 	v4l2_i2c_subdev_init(&ov5675->sd, client, &ov5675_subdev_ops);
13495525fd86SBingbu Cao 
135049d9ad71SQuentin Schulz 	ret = ov5675_power_on(&client->dev);
135149d9ad71SQuentin Schulz 	if (ret) {
135249d9ad71SQuentin Schulz 		dev_err(&client->dev, "failed to power on: %d\n", ret);
135349d9ad71SQuentin Schulz 		return ret;
135449d9ad71SQuentin Schulz 	}
135549d9ad71SQuentin Schulz 
13565525fd86SBingbu Cao 	full_power = acpi_dev_state_d0(&client->dev);
13575525fd86SBingbu Cao 	if (full_power) {
1358bf27502bSShawn Tu 		ret = ov5675_identify_module(ov5675);
1359bf27502bSShawn Tu 		if (ret) {
1360bf27502bSShawn Tu 			dev_err(&client->dev, "failed to find sensor: %d", ret);
136149d9ad71SQuentin Schulz 			goto probe_power_off;
1362bf27502bSShawn Tu 		}
13635525fd86SBingbu Cao 	}
1364bf27502bSShawn Tu 
1365bf27502bSShawn Tu 	mutex_init(&ov5675->mutex);
1366bf27502bSShawn Tu 	ov5675->cur_mode = &supported_modes[0];
1367bf27502bSShawn Tu 	ret = ov5675_init_controls(ov5675);
1368bf27502bSShawn Tu 	if (ret) {
1369bf27502bSShawn Tu 		dev_err(&client->dev, "failed to init controls: %d", ret);
1370bf27502bSShawn Tu 		goto probe_error_v4l2_ctrl_handler_free;
1371bf27502bSShawn Tu 	}
1372bf27502bSShawn Tu 
1373bf27502bSShawn Tu 	ov5675->sd.internal_ops = &ov5675_internal_ops;
1374bf27502bSShawn Tu 	ov5675->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1375bf27502bSShawn Tu 	ov5675->sd.entity.ops = &ov5675_subdev_entity_ops;
1376bf27502bSShawn Tu 	ov5675->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
1377bf27502bSShawn Tu 	ov5675->pad.flags = MEDIA_PAD_FL_SOURCE;
1378bf27502bSShawn Tu 	ret = media_entity_pads_init(&ov5675->sd.entity, 1, &ov5675->pad);
1379bf27502bSShawn Tu 	if (ret) {
1380bf27502bSShawn Tu 		dev_err(&client->dev, "failed to init entity pads: %d", ret);
1381bf27502bSShawn Tu 		goto probe_error_v4l2_ctrl_handler_free;
1382bf27502bSShawn Tu 	}
1383bf27502bSShawn Tu 
138415786f7bSSakari Ailus 	ret = v4l2_async_register_subdev_sensor(&ov5675->sd);
1385bf27502bSShawn Tu 	if (ret < 0) {
1386bf27502bSShawn Tu 		dev_err(&client->dev, "failed to register V4L2 subdev: %d",
1387bf27502bSShawn Tu 			ret);
1388bf27502bSShawn Tu 		goto probe_error_media_entity_cleanup;
1389bf27502bSShawn Tu 	}
1390bf27502bSShawn Tu 
13915525fd86SBingbu Cao 	/* Set the device's state to active if it's in D0 state. */
13925525fd86SBingbu Cao 	if (full_power)
1393bf27502bSShawn Tu 		pm_runtime_set_active(&client->dev);
1394bf27502bSShawn Tu 	pm_runtime_enable(&client->dev);
1395bf27502bSShawn Tu 	pm_runtime_idle(&client->dev);
1396bf27502bSShawn Tu 
1397bf27502bSShawn Tu 	return 0;
1398bf27502bSShawn Tu 
1399bf27502bSShawn Tu probe_error_media_entity_cleanup:
1400bf27502bSShawn Tu 	media_entity_cleanup(&ov5675->sd.entity);
1401bf27502bSShawn Tu 
1402bf27502bSShawn Tu probe_error_v4l2_ctrl_handler_free:
1403bf27502bSShawn Tu 	v4l2_ctrl_handler_free(ov5675->sd.ctrl_handler);
1404bf27502bSShawn Tu 	mutex_destroy(&ov5675->mutex);
140549d9ad71SQuentin Schulz probe_power_off:
140649d9ad71SQuentin Schulz 	ov5675_power_off(&client->dev);
1407bf27502bSShawn Tu 
1408bf27502bSShawn Tu 	return ret;
1409bf27502bSShawn Tu }
1410bf27502bSShawn Tu 
1411bf27502bSShawn Tu static const struct dev_pm_ops ov5675_pm_ops = {
1412bf27502bSShawn Tu 	SET_SYSTEM_SLEEP_PM_OPS(ov5675_suspend, ov5675_resume)
141349d9ad71SQuentin Schulz 	SET_RUNTIME_PM_OPS(ov5675_power_off, ov5675_power_on, NULL)
1414bf27502bSShawn Tu };
1415bf27502bSShawn Tu 
1416bf27502bSShawn Tu #ifdef CONFIG_ACPI
1417bf27502bSShawn Tu static const struct acpi_device_id ov5675_acpi_ids[] = {
1418bf27502bSShawn Tu 	{"OVTI5675"},
1419bf27502bSShawn Tu 	{}
1420bf27502bSShawn Tu };
1421bf27502bSShawn Tu 
1422bf27502bSShawn Tu MODULE_DEVICE_TABLE(acpi, ov5675_acpi_ids);
1423bf27502bSShawn Tu #endif
1424bf27502bSShawn Tu 
142549d9ad71SQuentin Schulz static const struct of_device_id ov5675_of_match[] = {
142649d9ad71SQuentin Schulz 	{ .compatible = "ovti,ov5675", },
142749d9ad71SQuentin Schulz 	{ /* sentinel */ },
142849d9ad71SQuentin Schulz };
142949d9ad71SQuentin Schulz MODULE_DEVICE_TABLE(of, ov5675_of_match);
143049d9ad71SQuentin Schulz 
1431bf27502bSShawn Tu static struct i2c_driver ov5675_i2c_driver = {
1432bf27502bSShawn Tu 	.driver = {
1433bf27502bSShawn Tu 		.name = "ov5675",
1434bf27502bSShawn Tu 		.pm = &ov5675_pm_ops,
1435bf27502bSShawn Tu 		.acpi_match_table = ACPI_PTR(ov5675_acpi_ids),
143649d9ad71SQuentin Schulz 		.of_match_table = ov5675_of_match,
1437bf27502bSShawn Tu 	},
1438aaeb31c0SUwe Kleine-König 	.probe = ov5675_probe,
1439bf27502bSShawn Tu 	.remove = ov5675_remove,
14405525fd86SBingbu Cao 	.flags = I2C_DRV_ACPI_WAIVE_D0_PROBE,
1441bf27502bSShawn Tu };
1442bf27502bSShawn Tu 
1443bf27502bSShawn Tu module_i2c_driver(ov5675_i2c_driver);
1444bf27502bSShawn Tu 
1445*4106cd72SSakari Ailus MODULE_AUTHOR("Shawn Tu");
1446bf27502bSShawn Tu MODULE_DESCRIPTION("OmniVision OV5675 sensor driver");
1447bf27502bSShawn Tu MODULE_LICENSE("GPL v2");
1448