xref: /openbmc/linux/drivers/media/i2c/ov5648.c (revision aaeb31c0)
1e43ccb0aSPaul Kocialkowski // SPDX-License-Identifier: GPL-2.0-or-later
2e43ccb0aSPaul Kocialkowski /*
3e43ccb0aSPaul Kocialkowski  * Copyright (C) 2020 Bootlin
4e43ccb0aSPaul Kocialkowski  * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
5e43ccb0aSPaul Kocialkowski  */
6e43ccb0aSPaul Kocialkowski 
7e43ccb0aSPaul Kocialkowski #include <linux/clk.h>
8e43ccb0aSPaul Kocialkowski #include <linux/delay.h>
9e43ccb0aSPaul Kocialkowski #include <linux/device.h>
10e43ccb0aSPaul Kocialkowski #include <linux/i2c.h>
11e43ccb0aSPaul Kocialkowski #include <linux/module.h>
12e43ccb0aSPaul Kocialkowski #include <linux/of_graph.h>
13e43ccb0aSPaul Kocialkowski #include <linux/pm_runtime.h>
14e43ccb0aSPaul Kocialkowski #include <linux/regulator/consumer.h>
15e43ccb0aSPaul Kocialkowski #include <linux/videodev2.h>
16e43ccb0aSPaul Kocialkowski #include <media/v4l2-ctrls.h>
17e43ccb0aSPaul Kocialkowski #include <media/v4l2-device.h>
18e43ccb0aSPaul Kocialkowski #include <media/v4l2-fwnode.h>
19e43ccb0aSPaul Kocialkowski #include <media/v4l2-image-sizes.h>
20e43ccb0aSPaul Kocialkowski #include <media/v4l2-mediabus.h>
21e43ccb0aSPaul Kocialkowski 
22e43ccb0aSPaul Kocialkowski /* Clock rate */
23e43ccb0aSPaul Kocialkowski 
24e43ccb0aSPaul Kocialkowski #define OV5648_XVCLK_RATE			24000000
25e43ccb0aSPaul Kocialkowski 
26e43ccb0aSPaul Kocialkowski /* Register definitions */
27e43ccb0aSPaul Kocialkowski 
28e43ccb0aSPaul Kocialkowski /* System */
29e43ccb0aSPaul Kocialkowski 
30e43ccb0aSPaul Kocialkowski #define OV5648_SW_STANDBY_REG			0x100
31e43ccb0aSPaul Kocialkowski #define OV5648_SW_STANDBY_STREAM_ON		BIT(0)
32e43ccb0aSPaul Kocialkowski 
33e43ccb0aSPaul Kocialkowski #define OV5648_SW_RESET_REG			0x103
34e43ccb0aSPaul Kocialkowski #define OV5648_SW_RESET_RESET			BIT(0)
35e43ccb0aSPaul Kocialkowski 
36e43ccb0aSPaul Kocialkowski #define OV5648_PAD_OEN0_REG			0x3000
37e43ccb0aSPaul Kocialkowski #define OV5648_PAD_OEN1_REG			0x3001
38e43ccb0aSPaul Kocialkowski #define OV5648_PAD_OEN2_REG			0x3002
39e43ccb0aSPaul Kocialkowski #define OV5648_PAD_OUT0_REG			0x3008
40e43ccb0aSPaul Kocialkowski #define OV5648_PAD_OUT1_REG			0x3009
41e43ccb0aSPaul Kocialkowski 
42e43ccb0aSPaul Kocialkowski #define OV5648_CHIP_ID_H_REG			0x300a
43e43ccb0aSPaul Kocialkowski #define OV5648_CHIP_ID_H_VALUE			0x56
44e43ccb0aSPaul Kocialkowski #define OV5648_CHIP_ID_L_REG			0x300b
45e43ccb0aSPaul Kocialkowski #define OV5648_CHIP_ID_L_VALUE			0x48
46e43ccb0aSPaul Kocialkowski 
47e43ccb0aSPaul Kocialkowski #define OV5648_PAD_OUT2_REG			0x300d
48e43ccb0aSPaul Kocialkowski #define OV5648_PAD_SEL0_REG			0x300e
49e43ccb0aSPaul Kocialkowski #define OV5648_PAD_SEL1_REG			0x300f
50e43ccb0aSPaul Kocialkowski #define OV5648_PAD_SEL2_REG			0x3010
51e43ccb0aSPaul Kocialkowski #define OV5648_PAD_PK_REG			0x3011
52e43ccb0aSPaul Kocialkowski #define OV5648_PAD_PK_PD_DATO_EN		BIT(7)
53e43ccb0aSPaul Kocialkowski #define OV5648_PAD_PK_DRIVE_STRENGTH_1X		(0 << 5)
54e43ccb0aSPaul Kocialkowski #define OV5648_PAD_PK_DRIVE_STRENGTH_2X		(2 << 5)
55e43ccb0aSPaul Kocialkowski #define OV5648_PAD_PK_FREX_N			BIT(1)
56e43ccb0aSPaul Kocialkowski 
57e43ccb0aSPaul Kocialkowski #define OV5648_A_PWC_PK_O0_REG			0x3013
58e43ccb0aSPaul Kocialkowski #define OV5648_A_PWC_PK_O0_BP_REGULATOR_N	BIT(3)
59e43ccb0aSPaul Kocialkowski #define OV5648_A_PWC_PK_O1_REG			0x3014
60e43ccb0aSPaul Kocialkowski 
61e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_PHY0_REG			0x3016
62e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_PHY1_REG			0x3017
63e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_SC_CTRL0_REG		0x3018
64e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_SC_CTRL0_MIPI_LANES(v)	(((v) << 5) & GENMASK(7, 5))
65e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_SC_CTRL0_PHY_HS_TX_PD	BIT(4)
66e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_SC_CTRL0_PHY_LP_RX_PD	BIT(3)
67e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_SC_CTRL0_MIPI_EN		BIT(2)
68e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_SC_CTRL0_MIPI_SUSP		BIT(1)
69e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_SC_CTRL0_LANE_DIS_OP	BIT(0)
70e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_SC_CTRL1_REG		0x3019
71e43ccb0aSPaul Kocialkowski #define OV5648_MISC_CTRL0_REG			0x3021
72e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_SC_CTRL2_REG		0x3022
73e43ccb0aSPaul Kocialkowski #define OV5648_SUB_ID_REG			0x302a
74e43ccb0aSPaul Kocialkowski 
75e43ccb0aSPaul Kocialkowski #define OV5648_PLL_CTRL0_REG			0x3034
76e43ccb0aSPaul Kocialkowski #define OV5648_PLL_CTRL0_PLL_CHARGE_PUMP(v)	(((v) << 4) & GENMASK(6, 4))
77e43ccb0aSPaul Kocialkowski #define OV5648_PLL_CTRL0_BITS(v)		((v) & GENMASK(3, 0))
78e43ccb0aSPaul Kocialkowski #define OV5648_PLL_CTRL1_REG			0x3035
79e43ccb0aSPaul Kocialkowski #define OV5648_PLL_CTRL1_SYS_DIV(v)		(((v) << 4) & GENMASK(7, 4))
80e43ccb0aSPaul Kocialkowski #define OV5648_PLL_CTRL1_MIPI_DIV(v)		((v) & GENMASK(3, 0))
81e43ccb0aSPaul Kocialkowski #define OV5648_PLL_MUL_REG			0x3036
82e43ccb0aSPaul Kocialkowski #define OV5648_PLL_MUL(v)			((v) & GENMASK(7, 0))
83e43ccb0aSPaul Kocialkowski #define OV5648_PLL_DIV_REG			0x3037
84e43ccb0aSPaul Kocialkowski #define OV5648_PLL_DIV_ROOT_DIV(v)		((((v) - 1) << 4) & BIT(4))
85e43ccb0aSPaul Kocialkowski #define OV5648_PLL_DIV_PLL_PRE_DIV(v)		((v) & GENMASK(3, 0))
86e43ccb0aSPaul Kocialkowski #define OV5648_PLL_DEBUG_REG			0x3038
87e43ccb0aSPaul Kocialkowski #define OV5648_PLL_BYPASS_REG			0x3039
88e43ccb0aSPaul Kocialkowski 
89e43ccb0aSPaul Kocialkowski #define OV5648_PLLS_BYPASS_REG			0x303a
90e43ccb0aSPaul Kocialkowski #define OV5648_PLLS_MUL_REG			0x303b
91e43ccb0aSPaul Kocialkowski #define OV5648_PLLS_MUL(v)			((v) & GENMASK(4, 0))
92e43ccb0aSPaul Kocialkowski #define OV5648_PLLS_CTRL_REG			0x303c
93e43ccb0aSPaul Kocialkowski #define OV5648_PLLS_CTRL_PLL_CHARGE_PUMP(v)	(((v) << 4) & GENMASK(6, 4))
94e43ccb0aSPaul Kocialkowski #define OV5648_PLLS_CTRL_SYS_DIV(v)		((v) & GENMASK(3, 0))
95e43ccb0aSPaul Kocialkowski #define OV5648_PLLS_DIV_REG			0x303d
96e43ccb0aSPaul Kocialkowski #define OV5648_PLLS_DIV_PLLS_PRE_DIV(v)		(((v) << 4) & GENMASK(5, 4))
97e43ccb0aSPaul Kocialkowski #define OV5648_PLLS_DIV_PLLS_DIV_R(v)		((((v) - 1) << 2) & BIT(2))
98e43ccb0aSPaul Kocialkowski #define OV5648_PLLS_DIV_PLLS_SEL_DIV(v)		((v) & GENMASK(1, 0))
99e43ccb0aSPaul Kocialkowski 
100e43ccb0aSPaul Kocialkowski #define OV5648_SRB_CTRL_REG			0x3106
101e43ccb0aSPaul Kocialkowski #define OV5648_SRB_CTRL_SCLK_DIV(v)		(((v) << 2) & GENMASK(3, 2))
102e43ccb0aSPaul Kocialkowski #define OV5648_SRB_CTRL_RESET_ARBITER_EN	BIT(1)
103e43ccb0aSPaul Kocialkowski #define OV5648_SRB_CTRL_SCLK_ARBITER_EN		BIT(0)
104e43ccb0aSPaul Kocialkowski 
105e43ccb0aSPaul Kocialkowski /* Group Hold */
106e43ccb0aSPaul Kocialkowski 
107e43ccb0aSPaul Kocialkowski #define OV5648_GROUP_ADR0_REG			0x3200
108e43ccb0aSPaul Kocialkowski #define OV5648_GROUP_ADR1_REG			0x3201
109e43ccb0aSPaul Kocialkowski #define OV5648_GROUP_ADR2_REG			0x3202
110e43ccb0aSPaul Kocialkowski #define OV5648_GROUP_ADR3_REG			0x3203
111e43ccb0aSPaul Kocialkowski #define OV5648_GROUP_LEN0_REG			0x3204
112e43ccb0aSPaul Kocialkowski #define OV5648_GROUP_LEN1_REG			0x3205
113e43ccb0aSPaul Kocialkowski #define OV5648_GROUP_LEN2_REG			0x3206
114e43ccb0aSPaul Kocialkowski #define OV5648_GROUP_LEN3_REG			0x3207
115e43ccb0aSPaul Kocialkowski #define OV5648_GROUP_ACCESS_REG			0x3208
116e43ccb0aSPaul Kocialkowski 
117e43ccb0aSPaul Kocialkowski /* Exposure/gain/banding */
118e43ccb0aSPaul Kocialkowski 
119e43ccb0aSPaul Kocialkowski #define OV5648_EXPOSURE_CTRL_HH_REG		0x3500
120e43ccb0aSPaul Kocialkowski #define OV5648_EXPOSURE_CTRL_HH(v)		(((v) & GENMASK(19, 16)) >> 16)
121e43ccb0aSPaul Kocialkowski #define OV5648_EXPOSURE_CTRL_HH_VALUE(v)	(((v) << 16) & GENMASK(19, 16))
122e43ccb0aSPaul Kocialkowski #define OV5648_EXPOSURE_CTRL_H_REG		0x3501
123e43ccb0aSPaul Kocialkowski #define OV5648_EXPOSURE_CTRL_H(v)		(((v) & GENMASK(15, 8)) >> 8)
124e43ccb0aSPaul Kocialkowski #define OV5648_EXPOSURE_CTRL_H_VALUE(v)		(((v) << 8) & GENMASK(15, 8))
125e43ccb0aSPaul Kocialkowski #define OV5648_EXPOSURE_CTRL_L_REG		0x3502
126e43ccb0aSPaul Kocialkowski #define OV5648_EXPOSURE_CTRL_L(v)		((v) & GENMASK(7, 0))
127e43ccb0aSPaul Kocialkowski #define OV5648_EXPOSURE_CTRL_L_VALUE(v)		((v) & GENMASK(7, 0))
128e43ccb0aSPaul Kocialkowski #define OV5648_MANUAL_CTRL_REG			0x3503
129e43ccb0aSPaul Kocialkowski #define OV5648_MANUAL_CTRL_FRAME_DELAY(v)	(((v) << 4) & GENMASK(5, 4))
130e43ccb0aSPaul Kocialkowski #define OV5648_MANUAL_CTRL_AGC_MANUAL_EN	BIT(1)
131e43ccb0aSPaul Kocialkowski #define OV5648_MANUAL_CTRL_AEC_MANUAL_EN	BIT(0)
132e43ccb0aSPaul Kocialkowski #define OV5648_GAIN_CTRL_H_REG			0x350a
133e43ccb0aSPaul Kocialkowski #define OV5648_GAIN_CTRL_H(v)			(((v) & GENMASK(9, 8)) >> 8)
134e43ccb0aSPaul Kocialkowski #define OV5648_GAIN_CTRL_H_VALUE(v)		(((v) << 8) & GENMASK(9, 8))
135e43ccb0aSPaul Kocialkowski #define OV5648_GAIN_CTRL_L_REG			0x350b
136e43ccb0aSPaul Kocialkowski #define OV5648_GAIN_CTRL_L(v)			((v) & GENMASK(7, 0))
137e43ccb0aSPaul Kocialkowski #define OV5648_GAIN_CTRL_L_VALUE(v)		((v) & GENMASK(7, 0))
138e43ccb0aSPaul Kocialkowski 
139e43ccb0aSPaul Kocialkowski #define OV5648_ANALOG_CTRL0_REG_BASE		0x3600
140e43ccb0aSPaul Kocialkowski #define OV5648_ANALOG_CTRL1_REG_BASE		0x3700
141e43ccb0aSPaul Kocialkowski 
142e43ccb0aSPaul Kocialkowski #define OV5648_AEC_CTRL0_REG			0x3a00
143e43ccb0aSPaul Kocialkowski #define OV5648_AEC_CTRL0_DEBUG			BIT(6)
144e43ccb0aSPaul Kocialkowski #define OV5648_AEC_CTRL0_DEBAND_EN		BIT(5)
145e43ccb0aSPaul Kocialkowski #define OV5648_AEC_CTRL0_DEBAND_LOW_LIMIT_EN	BIT(4)
146e43ccb0aSPaul Kocialkowski #define OV5648_AEC_CTRL0_START_SEL_EN		BIT(3)
147e43ccb0aSPaul Kocialkowski #define OV5648_AEC_CTRL0_NIGHT_MODE_EN		BIT(2)
148e43ccb0aSPaul Kocialkowski #define OV5648_AEC_CTRL0_FREEZE_EN		BIT(0)
149e43ccb0aSPaul Kocialkowski #define OV5648_EXPOSURE_MIN_REG			0x3a01
150e43ccb0aSPaul Kocialkowski #define OV5648_EXPOSURE_MAX_60_H_REG		0x3a02
151e43ccb0aSPaul Kocialkowski #define OV5648_EXPOSURE_MAX_60_L_REG		0x3a03
152e43ccb0aSPaul Kocialkowski #define OV5648_AEC_CTRL5_REG			0x3a05
153e43ccb0aSPaul Kocialkowski #define OV5648_AEC_CTRL6_REG			0x3a06
154e43ccb0aSPaul Kocialkowski #define OV5648_AEC_CTRL7_REG			0x3a07
155e43ccb0aSPaul Kocialkowski #define OV5648_BANDING_STEP_50_H_REG		0x3a08
156e43ccb0aSPaul Kocialkowski #define OV5648_BANDING_STEP_50_L_REG		0x3a09
157e43ccb0aSPaul Kocialkowski #define OV5648_BANDING_STEP_60_H_REG		0x3a0a
158e43ccb0aSPaul Kocialkowski #define OV5648_BANDING_STEP_60_L_REG		0x3a0b
159e43ccb0aSPaul Kocialkowski #define OV5648_AEC_CTRLC_REG			0x3a0c
160e43ccb0aSPaul Kocialkowski #define OV5648_BANDING_MAX_60_REG		0x3a0d
161e43ccb0aSPaul Kocialkowski #define OV5648_BANDING_MAX_50_REG		0x3a0e
162e43ccb0aSPaul Kocialkowski #define OV5648_WPT_REG				0x3a0f
163e43ccb0aSPaul Kocialkowski #define OV5648_BPT_REG				0x3a10
164e43ccb0aSPaul Kocialkowski #define OV5648_VPT_HIGH_REG			0x3a11
165e43ccb0aSPaul Kocialkowski #define OV5648_AVG_MANUAL_REG			0x3a12
166e43ccb0aSPaul Kocialkowski #define OV5648_PRE_GAIN_REG			0x3a13
167e43ccb0aSPaul Kocialkowski #define OV5648_EXPOSURE_MAX_50_H_REG		0x3a14
168e43ccb0aSPaul Kocialkowski #define OV5648_EXPOSURE_MAX_50_L_REG		0x3a15
169e43ccb0aSPaul Kocialkowski #define OV5648_GAIN_BASE_NIGHT_REG		0x3a17
170e43ccb0aSPaul Kocialkowski #define OV5648_AEC_GAIN_CEILING_H_REG		0x3a18
171e43ccb0aSPaul Kocialkowski #define OV5648_AEC_GAIN_CEILING_L_REG		0x3a19
172e43ccb0aSPaul Kocialkowski #define OV5648_DIFF_MAX_REG			0x3a1a
173e43ccb0aSPaul Kocialkowski #define OV5648_WPT2_REG				0x3a1b
174e43ccb0aSPaul Kocialkowski #define OV5648_LED_ADD_ROW_H_REG		0x3a1c
175e43ccb0aSPaul Kocialkowski #define OV5648_LED_ADD_ROW_L_REG		0x3a1d
176e43ccb0aSPaul Kocialkowski #define OV5648_BPT2_REG				0x3a1e
177e43ccb0aSPaul Kocialkowski #define OV5648_VPT_LOW_REG			0x3a1f
178e43ccb0aSPaul Kocialkowski #define OV5648_AEC_CTRL20_REG			0x3a20
179e43ccb0aSPaul Kocialkowski #define OV5648_AEC_CTRL21_REG			0x3a21
180e43ccb0aSPaul Kocialkowski 
181e43ccb0aSPaul Kocialkowski #define OV5648_AVG_START_X_H_REG		0x5680
182e43ccb0aSPaul Kocialkowski #define OV5648_AVG_START_X_L_REG		0x5681
183e43ccb0aSPaul Kocialkowski #define OV5648_AVG_START_Y_H_REG		0x5682
184e43ccb0aSPaul Kocialkowski #define OV5648_AVG_START_Y_L_REG		0x5683
185e43ccb0aSPaul Kocialkowski #define OV5648_AVG_WINDOW_X_H_REG		0x5684
186e43ccb0aSPaul Kocialkowski #define OV5648_AVG_WINDOW_X_L_REG		0x5685
187e43ccb0aSPaul Kocialkowski #define OV5648_AVG_WINDOW_Y_H_REG		0x5686
188e43ccb0aSPaul Kocialkowski #define OV5648_AVG_WINDOW_Y_L_REG		0x5687
189e43ccb0aSPaul Kocialkowski #define OV5648_AVG_WEIGHT00_REG			0x5688
190e43ccb0aSPaul Kocialkowski #define OV5648_AVG_WEIGHT01_REG			0x5689
191e43ccb0aSPaul Kocialkowski #define OV5648_AVG_WEIGHT02_REG			0x568a
192e43ccb0aSPaul Kocialkowski #define OV5648_AVG_WEIGHT03_REG			0x568b
193e43ccb0aSPaul Kocialkowski #define OV5648_AVG_WEIGHT04_REG			0x568c
194e43ccb0aSPaul Kocialkowski #define OV5648_AVG_WEIGHT05_REG			0x568d
195e43ccb0aSPaul Kocialkowski #define OV5648_AVG_WEIGHT06_REG			0x568e
196e43ccb0aSPaul Kocialkowski #define OV5648_AVG_WEIGHT07_REG			0x568f
197e43ccb0aSPaul Kocialkowski #define OV5648_AVG_CTRL10_REG			0x5690
198e43ccb0aSPaul Kocialkowski #define OV5648_AVG_WEIGHT_SUM_REG		0x5691
199e43ccb0aSPaul Kocialkowski #define OV5648_AVG_READOUT_REG			0x5693
200e43ccb0aSPaul Kocialkowski 
201e43ccb0aSPaul Kocialkowski #define OV5648_DIG_CTRL0_REG			0x5a00
202e43ccb0aSPaul Kocialkowski #define OV5648_DIG_COMP_MAN_H_REG		0x5a02
203e43ccb0aSPaul Kocialkowski #define OV5648_DIG_COMP_MAN_L_REG		0x5a03
204e43ccb0aSPaul Kocialkowski 
205e43ccb0aSPaul Kocialkowski #define OV5648_GAINC_MAN_H_REG			0x5a20
206e43ccb0aSPaul Kocialkowski #define OV5648_GAINC_MAN_L_REG			0x5a21
207e43ccb0aSPaul Kocialkowski #define OV5648_GAINC_DGC_MAN_H_REG		0x5a22
208e43ccb0aSPaul Kocialkowski #define OV5648_GAINC_DGC_MAN_L_REG		0x5a23
209e43ccb0aSPaul Kocialkowski #define OV5648_GAINC_CTRL0_REG			0x5a24
210e43ccb0aSPaul Kocialkowski 
211e43ccb0aSPaul Kocialkowski #define OV5648_GAINF_ANA_NUM_REG		0x5a40
212e43ccb0aSPaul Kocialkowski #define OV5648_GAINF_DIG_GAIN_REG		0x5a41
213e43ccb0aSPaul Kocialkowski 
214e43ccb0aSPaul Kocialkowski /* Timing */
215e43ccb0aSPaul Kocialkowski 
216e43ccb0aSPaul Kocialkowski #define OV5648_CROP_START_X_H_REG		0x3800
217e43ccb0aSPaul Kocialkowski #define OV5648_CROP_START_X_H(v)		(((v) & GENMASK(11, 8)) >> 8)
218e43ccb0aSPaul Kocialkowski #define OV5648_CROP_START_X_L_REG		0x3801
219e43ccb0aSPaul Kocialkowski #define OV5648_CROP_START_X_L(v)		((v) & GENMASK(7, 0))
220e43ccb0aSPaul Kocialkowski #define OV5648_CROP_START_Y_H_REG		0x3802
221e43ccb0aSPaul Kocialkowski #define OV5648_CROP_START_Y_H(v)		(((v) & GENMASK(11, 8)) >> 8)
222e43ccb0aSPaul Kocialkowski #define OV5648_CROP_START_Y_L_REG		0x3803
223e43ccb0aSPaul Kocialkowski #define OV5648_CROP_START_Y_L(v)		((v) & GENMASK(7, 0))
224e43ccb0aSPaul Kocialkowski #define OV5648_CROP_END_X_H_REG			0x3804
225e43ccb0aSPaul Kocialkowski #define OV5648_CROP_END_X_H(v)			(((v) & GENMASK(11, 8)) >> 8)
226e43ccb0aSPaul Kocialkowski #define OV5648_CROP_END_X_L_REG			0x3805
227e43ccb0aSPaul Kocialkowski #define OV5648_CROP_END_X_L(v)			((v) & GENMASK(7, 0))
228e43ccb0aSPaul Kocialkowski #define OV5648_CROP_END_Y_H_REG			0x3806
229e43ccb0aSPaul Kocialkowski #define OV5648_CROP_END_Y_H(v)			(((v) & GENMASK(11, 8)) >> 8)
230e43ccb0aSPaul Kocialkowski #define OV5648_CROP_END_Y_L_REG			0x3807
231e43ccb0aSPaul Kocialkowski #define OV5648_CROP_END_Y_L(v)			((v) & GENMASK(7, 0))
232e43ccb0aSPaul Kocialkowski #define OV5648_OUTPUT_SIZE_X_H_REG		0x3808
233e43ccb0aSPaul Kocialkowski #define OV5648_OUTPUT_SIZE_X_H(v)		(((v) & GENMASK(11, 8)) >> 8)
234e43ccb0aSPaul Kocialkowski #define OV5648_OUTPUT_SIZE_X_L_REG		0x3809
235e43ccb0aSPaul Kocialkowski #define OV5648_OUTPUT_SIZE_X_L(v)		((v) & GENMASK(7, 0))
236e43ccb0aSPaul Kocialkowski #define OV5648_OUTPUT_SIZE_Y_H_REG		0x380a
237e43ccb0aSPaul Kocialkowski #define OV5648_OUTPUT_SIZE_Y_H(v)		(((v) & GENMASK(11, 8)) >> 8)
238e43ccb0aSPaul Kocialkowski #define OV5648_OUTPUT_SIZE_Y_L_REG		0x380b
239e43ccb0aSPaul Kocialkowski #define OV5648_OUTPUT_SIZE_Y_L(v)		((v) & GENMASK(7, 0))
240e43ccb0aSPaul Kocialkowski #define OV5648_HTS_H_REG			0x380c
241e43ccb0aSPaul Kocialkowski #define OV5648_HTS_H(v)				(((v) & GENMASK(12, 8)) >> 8)
242e43ccb0aSPaul Kocialkowski #define OV5648_HTS_L_REG			0x380d
243e43ccb0aSPaul Kocialkowski #define OV5648_HTS_L(v)				((v) & GENMASK(7, 0))
244e43ccb0aSPaul Kocialkowski #define OV5648_VTS_H_REG			0x380e
245e43ccb0aSPaul Kocialkowski #define OV5648_VTS_H(v)				(((v) & GENMASK(15, 8)) >> 8)
246e43ccb0aSPaul Kocialkowski #define OV5648_VTS_L_REG			0x380f
247e43ccb0aSPaul Kocialkowski #define OV5648_VTS_L(v)				((v) & GENMASK(7, 0))
248e43ccb0aSPaul Kocialkowski #define OV5648_OFFSET_X_H_REG			0x3810
249e43ccb0aSPaul Kocialkowski #define OV5648_OFFSET_X_H(v)			(((v) & GENMASK(11, 8)) >> 8)
250e43ccb0aSPaul Kocialkowski #define OV5648_OFFSET_X_L_REG			0x3811
251e43ccb0aSPaul Kocialkowski #define OV5648_OFFSET_X_L(v)			((v) & GENMASK(7, 0))
252e43ccb0aSPaul Kocialkowski #define OV5648_OFFSET_Y_H_REG			0x3812
253e43ccb0aSPaul Kocialkowski #define OV5648_OFFSET_Y_H(v)			(((v) & GENMASK(11, 8)) >> 8)
254e43ccb0aSPaul Kocialkowski #define OV5648_OFFSET_Y_L_REG			0x3813
255e43ccb0aSPaul Kocialkowski #define OV5648_OFFSET_Y_L(v)			((v) & GENMASK(7, 0))
256e43ccb0aSPaul Kocialkowski #define OV5648_SUB_INC_X_REG			0x3814
257e43ccb0aSPaul Kocialkowski #define OV5648_SUB_INC_X_ODD(v)			(((v) << 4) & GENMASK(7, 4))
258e43ccb0aSPaul Kocialkowski #define OV5648_SUB_INC_X_EVEN(v)		((v) & GENMASK(3, 0))
259e43ccb0aSPaul Kocialkowski #define OV5648_SUB_INC_Y_REG			0x3815
260e43ccb0aSPaul Kocialkowski #define OV5648_SUB_INC_Y_ODD(v)			(((v) << 4) & GENMASK(7, 4))
261e43ccb0aSPaul Kocialkowski #define OV5648_SUB_INC_Y_EVEN(v)		((v) & GENMASK(3, 0))
262e43ccb0aSPaul Kocialkowski #define OV5648_HSYNCST_H_REG			0x3816
263e43ccb0aSPaul Kocialkowski #define OV5648_HSYNCST_H(v)			(((v) >> 8) & 0xf)
264e43ccb0aSPaul Kocialkowski #define OV5648_HSYNCST_L_REG			0x3817
265e43ccb0aSPaul Kocialkowski #define OV5648_HSYNCST_L(v)			((v) & GENMASK(7, 0))
266e43ccb0aSPaul Kocialkowski #define OV5648_HSYNCW_H_REG			0x3818
267e43ccb0aSPaul Kocialkowski #define OV5648_HSYNCW_H(v)			(((v) >> 8) & 0xf)
268e43ccb0aSPaul Kocialkowski #define OV5648_HSYNCW_L_REG			0x3819
269e43ccb0aSPaul Kocialkowski #define OV5648_HSYNCW_L(v)			((v) & GENMASK(7, 0))
270e43ccb0aSPaul Kocialkowski 
271e43ccb0aSPaul Kocialkowski #define OV5648_TC20_REG				0x3820
272e43ccb0aSPaul Kocialkowski #define OV5648_TC20_DEBUG			BIT(6)
273e43ccb0aSPaul Kocialkowski #define OV5648_TC20_FLIP_VERT_ISP_EN		BIT(2)
274e43ccb0aSPaul Kocialkowski #define OV5648_TC20_FLIP_VERT_SENSOR_EN		BIT(1)
275e43ccb0aSPaul Kocialkowski #define OV5648_TC20_BINNING_VERT_EN		BIT(0)
276e43ccb0aSPaul Kocialkowski #define OV5648_TC21_REG				0x3821
277e43ccb0aSPaul Kocialkowski #define OV5648_TC21_FLIP_HORZ_ISP_EN		BIT(2)
278e43ccb0aSPaul Kocialkowski #define OV5648_TC21_FLIP_HORZ_SENSOR_EN		BIT(1)
279e43ccb0aSPaul Kocialkowski #define OV5648_TC21_BINNING_HORZ_EN		BIT(0)
280e43ccb0aSPaul Kocialkowski 
281e43ccb0aSPaul Kocialkowski /* Strobe/exposure */
282e43ccb0aSPaul Kocialkowski 
283e43ccb0aSPaul Kocialkowski #define OV5648_STROBE_REG			0x3b00
284e43ccb0aSPaul Kocialkowski #define OV5648_FREX_EXP_HH_REG			0x3b01
285e43ccb0aSPaul Kocialkowski #define OV5648_SHUTTER_DLY_H_REG		0x3b02
286e43ccb0aSPaul Kocialkowski #define OV5648_SHUTTER_DLY_L_REG		0x3b03
287e43ccb0aSPaul Kocialkowski #define OV5648_FREX_EXP_H_REG			0x3b04
288e43ccb0aSPaul Kocialkowski #define OV5648_FREX_EXP_L_REG			0x3b05
289e43ccb0aSPaul Kocialkowski #define OV5648_FREX_CTRL_REG			0x3b06
290e43ccb0aSPaul Kocialkowski #define OV5648_FREX_MODE_SEL_REG		0x3b07
291e43ccb0aSPaul Kocialkowski #define OV5648_FREX_MODE_SEL_FREX_SA1		BIT(4)
292e43ccb0aSPaul Kocialkowski #define OV5648_FREX_MODE_SEL_FX1_FM_EN		BIT(3)
293e43ccb0aSPaul Kocialkowski #define OV5648_FREX_MODE_SEL_FREX_INV		BIT(2)
294e43ccb0aSPaul Kocialkowski #define OV5648_FREX_MODE_SEL_MODE1		0x0
295e43ccb0aSPaul Kocialkowski #define OV5648_FREX_MODE_SEL_MODE2		0x1
296e43ccb0aSPaul Kocialkowski #define OV5648_FREX_MODE_SEL_ROLLING		0x2
297e43ccb0aSPaul Kocialkowski #define OV5648_FREX_EXP_REQ_REG			0x3b08
298e43ccb0aSPaul Kocialkowski #define OV5648_FREX_SHUTTER_DLY_REG		0x3b09
299e43ccb0aSPaul Kocialkowski #define OV5648_FREX_RST_LEN_REG			0x3b0a
300e43ccb0aSPaul Kocialkowski #define OV5648_STROBE_WIDTH_HH_REG		0x3b0b
301e43ccb0aSPaul Kocialkowski #define OV5648_STROBE_WIDTH_H_REG		0x3b0c
302e43ccb0aSPaul Kocialkowski 
303e43ccb0aSPaul Kocialkowski /* OTP */
304e43ccb0aSPaul Kocialkowski 
305e43ccb0aSPaul Kocialkowski #define OV5648_OTP_DATA_REG_BASE		0x3d00
306e43ccb0aSPaul Kocialkowski #define OV5648_OTP_PROGRAM_CTRL_REG		0x3d80
307e43ccb0aSPaul Kocialkowski #define OV5648_OTP_LOAD_CTRL_REG		0x3d81
308e43ccb0aSPaul Kocialkowski 
309e43ccb0aSPaul Kocialkowski /* PSRAM */
310e43ccb0aSPaul Kocialkowski 
311e43ccb0aSPaul Kocialkowski #define OV5648_PSRAM_CTRL1_REG			0x3f01
312e43ccb0aSPaul Kocialkowski #define OV5648_PSRAM_CTRLF_REG			0x3f0f
313e43ccb0aSPaul Kocialkowski 
314e43ccb0aSPaul Kocialkowski /* Black Level */
315e43ccb0aSPaul Kocialkowski 
316e43ccb0aSPaul Kocialkowski #define OV5648_BLC_CTRL0_REG			0x4000
317e43ccb0aSPaul Kocialkowski #define OV5648_BLC_CTRL1_REG			0x4001
318e43ccb0aSPaul Kocialkowski #define OV5648_BLC_CTRL1_START_LINE(v)		((v) & GENMASK(5, 0))
319e43ccb0aSPaul Kocialkowski #define OV5648_BLC_CTRL2_REG			0x4002
320e43ccb0aSPaul Kocialkowski #define OV5648_BLC_CTRL2_AUTO_EN		BIT(6)
321e43ccb0aSPaul Kocialkowski #define OV5648_BLC_CTRL2_RESET_FRAME_NUM(v)	((v) & GENMASK(5, 0))
322e43ccb0aSPaul Kocialkowski #define OV5648_BLC_CTRL3_REG			0x4003
323e43ccb0aSPaul Kocialkowski #define OV5648_BLC_LINE_NUM_REG			0x4004
324e43ccb0aSPaul Kocialkowski #define OV5648_BLC_LINE_NUM(v)			((v) & GENMASK(7, 0))
325e43ccb0aSPaul Kocialkowski #define OV5648_BLC_CTRL5_REG			0x4005
326e43ccb0aSPaul Kocialkowski #define OV5648_BLC_CTRL5_UPDATE_EN		BIT(1)
327e43ccb0aSPaul Kocialkowski #define OV5648_BLC_LEVEL_REG			0x4009
328e43ccb0aSPaul Kocialkowski 
329e43ccb0aSPaul Kocialkowski /* Frame */
330e43ccb0aSPaul Kocialkowski 
331e43ccb0aSPaul Kocialkowski #define OV5648_FRAME_CTRL_REG			0x4200
332e43ccb0aSPaul Kocialkowski #define OV5648_FRAME_ON_NUM_REG			0x4201
333e43ccb0aSPaul Kocialkowski #define OV5648_FRAME_OFF_NUM_REG		0x4202
334e43ccb0aSPaul Kocialkowski 
335e43ccb0aSPaul Kocialkowski /* MIPI CSI-2 */
336e43ccb0aSPaul Kocialkowski 
337e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_CTRL0_REG			0x4800
338e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_CTRL0_CLK_LANE_AUTOGATE	BIT(5)
339e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_CTRL0_LANE_SYNC_EN		BIT(4)
340e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_CTRL0_LANE_SELECT_LANE1	0
341e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_CTRL0_LANE_SELECT_LANE2	BIT(3)
342e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_CTRL0_IDLE_LP00		0
343e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_CTRL0_IDLE_LP11		BIT(2)
344e43ccb0aSPaul Kocialkowski 
345e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_CTRL1_REG			0x4801
346e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_CTRL2_REG			0x4802
347e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_CTRL3_REG			0x4803
348e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_CTRL4_REG			0x4804
349e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_CTRL5_REG			0x4805
350e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_MAX_FRAME_COUNT_H_REG	0x4810
351e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_MAX_FRAME_COUNT_L_REG	0x4811
352e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_CTRL14_REG			0x4814
353e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_DT_SPKT_REG			0x4815
354e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_HS_ZERO_MIN_H_REG		0x4818
355e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_HS_ZERO_MIN_L_REG		0x4819
356e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_HS_TRAIN_MIN_H_REG		0x481a
357e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_HS_TRAIN_MIN_L_REG		0x481b
358e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_CLK_ZERO_MIN_H_REG		0x481c
359e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_CLK_ZERO_MIN_L_REG		0x481d
360e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_CLK_PREPARE_MIN_H_REG	0x481e
361e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_CLK_PREPARE_MIN_L_REG	0x481f
362e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_CLK_POST_MIN_H_REG		0x4820
363e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_CLK_POST_MIN_L_REG		0x4821
364e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_CLK_TRAIL_MIN_H_REG		0x4822
365e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_CLK_TRAIL_MIN_L_REG		0x4823
366e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_LPX_P_MIN_H_REG		0x4824
367e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_LPX_P_MIN_L_REG		0x4825
368e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_HS_PREPARE_MIN_H_REG	0x4826
369e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_HS_PREPARE_MIN_L_REG	0x4827
370e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_HS_EXIT_MIN_H_REG		0x4828
371e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_HS_EXIT_MIN_L_REG		0x4829
372e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_HS_ZERO_MIN_UI_REG		0x482a
373e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_HS_TRAIL_MIN_UI_REG		0x482b
374e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_CLK_ZERO_MIN_UI_REG		0x482c
375e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_CLK_PREPARE_MIN_UI_REG	0x482d
376e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_CLK_POST_MIN_UI_REG		0x482e
377e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_CLK_TRAIL_MIN_UI_REG	0x482f
378e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_LPX_P_MIN_UI_REG		0x4830
379e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_HS_PREPARE_MIN_UI_REG	0x4831
380e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_HS_EXIT_MIN_UI_REG		0x4832
381e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_REG_MIN_H_REG		0x4833
382e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_REG_MIN_L_REG		0x4834
383e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_REG_MAX_H_REG		0x4835
384e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_REG_MAX_L_REG		0x4836
385e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_PCLK_PERIOD_REG		0x4837
386e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_WKUP_DLY_REG		0x4838
387e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_LP_GPIO_REG			0x483b
388e43ccb0aSPaul Kocialkowski #define OV5648_MIPI_SNR_PCLK_DIV_REG		0x4843
389e43ccb0aSPaul Kocialkowski 
390e43ccb0aSPaul Kocialkowski /* ISP */
391e43ccb0aSPaul Kocialkowski 
392e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL0_REG			0x5000
393e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL0_BLACK_CORRECT_EN	BIT(2)
394e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL0_WHITE_CORRECT_EN	BIT(1)
395e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL1_REG			0x5001
396e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL1_AWB_EN			BIT(0)
397e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL2_REG			0x5002
398e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL2_WIN_EN			BIT(6)
399e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL2_OTP_EN			BIT(1)
400e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL2_AWB_GAIN_EN		BIT(0)
401e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL3_REG			0x5003
402e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL3_BUF_EN			BIT(3)
403e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL3_BIN_MAN_SET		BIT(2)
404e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL3_BIN_AUTO_EN		BIT(1)
405e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL4_REG			0x5004
406e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL5_REG			0x5005
407e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL6_REG			0x5006
408e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL7_REG			0x5007
409e43ccb0aSPaul Kocialkowski #define OV5648_ISP_MAN_OFFSET_X_H_REG		0x5008
410e43ccb0aSPaul Kocialkowski #define OV5648_ISP_MAN_OFFSET_X_L_REG		0x5009
411e43ccb0aSPaul Kocialkowski #define OV5648_ISP_MAN_OFFSET_Y_H_REG		0x500a
412e43ccb0aSPaul Kocialkowski #define OV5648_ISP_MAN_OFFSET_Y_L_REG		0x500b
413e43ccb0aSPaul Kocialkowski #define OV5648_ISP_MAN_WIN_OFFSET_X_H_REG	0x500c
414e43ccb0aSPaul Kocialkowski #define OV5648_ISP_MAN_WIN_OFFSET_X_L_REG	0x500d
415e43ccb0aSPaul Kocialkowski #define OV5648_ISP_MAN_WIN_OFFSET_Y_H_REG	0x500e
416e43ccb0aSPaul Kocialkowski #define OV5648_ISP_MAN_WIN_OFFSET_Y_L_REG	0x500f
417e43ccb0aSPaul Kocialkowski #define OV5648_ISP_MAN_WIN_OUTPUT_X_H_REG	0x5010
418e43ccb0aSPaul Kocialkowski #define OV5648_ISP_MAN_WIN_OUTPUT_X_L_REG	0x5011
419e43ccb0aSPaul Kocialkowski #define OV5648_ISP_MAN_WIN_OUTPUT_Y_H_REG	0x5012
420e43ccb0aSPaul Kocialkowski #define OV5648_ISP_MAN_WIN_OUTPUT_Y_L_REG	0x5013
421e43ccb0aSPaul Kocialkowski #define OV5648_ISP_MAN_INPUT_X_H_REG		0x5014
422e43ccb0aSPaul Kocialkowski #define OV5648_ISP_MAN_INPUT_X_L_REG		0x5015
423e43ccb0aSPaul Kocialkowski #define OV5648_ISP_MAN_INPUT_Y_H_REG		0x5016
424e43ccb0aSPaul Kocialkowski #define OV5648_ISP_MAN_INPUT_Y_L_REG		0x5017
425e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL18_REG			0x5018
426e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL19_REG			0x5019
427e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL1A_REG			0x501a
428e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL1D_REG			0x501d
429e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL1F_REG			0x501f
430e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL1F_OUTPUT_EN		3
431e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL25_REG			0x5025
432e43ccb0aSPaul Kocialkowski 
433e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL3D_REG			0x503d
434e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL3D_PATTERN_EN		BIT(7)
435e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL3D_ROLLING_BAR_EN	BIT(6)
436e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL3D_TRANSPARENT_MODE	BIT(5)
437e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL3D_SQUARES_BW_MODE	BIT(4)
438e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL3D_PATTERN_COLOR_BARS	0
439e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL3D_PATTERN_RANDOM_DATA	1
440e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL3D_PATTERN_COLOR_SQUARES	2
441e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL3D_PATTERN_INPUT		3
442e43ccb0aSPaul Kocialkowski 
443e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL3E_REG			0x503e
444e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL4B_REG			0x504b
445e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL4B_POST_BIN_H_EN		BIT(5)
446e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL4B_POST_BIN_V_EN		BIT(4)
447e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL4C_REG			0x504c
448e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL57_REG			0x5057
449e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL58_REG			0x5058
450e43ccb0aSPaul Kocialkowski #define OV5648_ISP_CTRL59_REG			0x5059
451e43ccb0aSPaul Kocialkowski 
452e43ccb0aSPaul Kocialkowski #define OV5648_ISP_WINDOW_START_X_H_REG		0x5980
453e43ccb0aSPaul Kocialkowski #define OV5648_ISP_WINDOW_START_X_L_REG		0x5981
454e43ccb0aSPaul Kocialkowski #define OV5648_ISP_WINDOW_START_Y_H_REG		0x5982
455e43ccb0aSPaul Kocialkowski #define OV5648_ISP_WINDOW_START_Y_L_REG		0x5983
456e43ccb0aSPaul Kocialkowski #define OV5648_ISP_WINDOW_WIN_X_H_REG		0x5984
457e43ccb0aSPaul Kocialkowski #define OV5648_ISP_WINDOW_WIN_X_L_REG		0x5985
458e43ccb0aSPaul Kocialkowski #define OV5648_ISP_WINDOW_WIN_Y_H_REG		0x5986
459e43ccb0aSPaul Kocialkowski #define OV5648_ISP_WINDOW_WIN_Y_L_REG		0x5987
460e43ccb0aSPaul Kocialkowski #define OV5648_ISP_WINDOW_MAN_REG		0x5988
461e43ccb0aSPaul Kocialkowski 
462e43ccb0aSPaul Kocialkowski /* White Balance */
463e43ccb0aSPaul Kocialkowski 
464e43ccb0aSPaul Kocialkowski #define OV5648_AWB_CTRL_REG			0x5180
465e43ccb0aSPaul Kocialkowski #define OV5648_AWB_CTRL_FAST_AWB		BIT(6)
466e43ccb0aSPaul Kocialkowski #define OV5648_AWB_CTRL_GAIN_FREEZE_EN		BIT(5)
467e43ccb0aSPaul Kocialkowski #define OV5648_AWB_CTRL_SUM_FREEZE_EN		BIT(4)
468e43ccb0aSPaul Kocialkowski #define OV5648_AWB_CTRL_GAIN_MANUAL_EN		BIT(3)
469e43ccb0aSPaul Kocialkowski 
470e43ccb0aSPaul Kocialkowski #define OV5648_AWB_DELTA_REG			0x5181
471e43ccb0aSPaul Kocialkowski #define OV5648_AWB_STABLE_RANGE_REG		0x5182
472e43ccb0aSPaul Kocialkowski #define OV5648_AWB_STABLE_RANGE_WIDE_REG	0x5183
473e43ccb0aSPaul Kocialkowski #define OV5648_HSIZE_MAN_REG			0x5185
474e43ccb0aSPaul Kocialkowski 
475e43ccb0aSPaul Kocialkowski #define OV5648_GAIN_RED_MAN_H_REG		0x5186
476e43ccb0aSPaul Kocialkowski #define OV5648_GAIN_RED_MAN_H(v)		(((v) & GENMASK(11, 8)) >> 8)
477e43ccb0aSPaul Kocialkowski #define OV5648_GAIN_RED_MAN_L_REG		0x5187
478e43ccb0aSPaul Kocialkowski #define OV5648_GAIN_RED_MAN_L(v)		((v) & GENMASK(7, 0))
479e43ccb0aSPaul Kocialkowski #define OV5648_GAIN_GREEN_MAN_H_REG		0x5188
480e43ccb0aSPaul Kocialkowski #define OV5648_GAIN_GREEN_MAN_H(v)		(((v) & GENMASK(11, 8)) >> 8)
481e43ccb0aSPaul Kocialkowski #define OV5648_GAIN_GREEN_MAN_L_REG		0x5189
482e43ccb0aSPaul Kocialkowski #define OV5648_GAIN_GREEN_MAN_L(v)		((v) & GENMASK(7, 0))
483e43ccb0aSPaul Kocialkowski #define OV5648_GAIN_BLUE_MAN_H_REG		0x518a
484e43ccb0aSPaul Kocialkowski #define OV5648_GAIN_BLUE_MAN_H(v)		(((v) & GENMASK(11, 8)) >> 8)
485e43ccb0aSPaul Kocialkowski #define OV5648_GAIN_BLUE_MAN_L_REG		0x518b
486e43ccb0aSPaul Kocialkowski #define OV5648_GAIN_BLUE_MAN_L(v)		((v) & GENMASK(7, 0))
487e43ccb0aSPaul Kocialkowski #define OV5648_GAIN_RED_LIMIT_REG		0x518c
488e43ccb0aSPaul Kocialkowski #define OV5648_GAIN_GREEN_LIMIT_REG		0x518d
489e43ccb0aSPaul Kocialkowski #define OV5648_GAIN_BLUE_LIMIT_REG		0x518e
490e43ccb0aSPaul Kocialkowski #define OV5648_AWB_FRAME_COUNT_REG		0x518f
491e43ccb0aSPaul Kocialkowski #define OV5648_AWB_BASE_MAN_REG			0x51df
492e43ccb0aSPaul Kocialkowski 
493e43ccb0aSPaul Kocialkowski /* Macros */
494e43ccb0aSPaul Kocialkowski 
495e43ccb0aSPaul Kocialkowski #define ov5648_subdev_sensor(s) \
496e43ccb0aSPaul Kocialkowski 	container_of(s, struct ov5648_sensor, subdev)
497e43ccb0aSPaul Kocialkowski 
498e43ccb0aSPaul Kocialkowski #define ov5648_ctrl_subdev(c) \
49936e4f2b2SPaul Kocialkowski 	(&container_of((c)->handler, struct ov5648_sensor, \
50036e4f2b2SPaul Kocialkowski 		       ctrls.handler)->subdev)
501e43ccb0aSPaul Kocialkowski 
502e43ccb0aSPaul Kocialkowski /* Data structures */
503e43ccb0aSPaul Kocialkowski 
504e43ccb0aSPaul Kocialkowski struct ov5648_register_value {
505e43ccb0aSPaul Kocialkowski 	u16 address;
506e43ccb0aSPaul Kocialkowski 	u8 value;
507e43ccb0aSPaul Kocialkowski 	unsigned int delay_ms;
508e43ccb0aSPaul Kocialkowski };
509e43ccb0aSPaul Kocialkowski 
510e43ccb0aSPaul Kocialkowski /*
511e43ccb0aSPaul Kocialkowski  * PLL1 Clock Tree:
512e43ccb0aSPaul Kocialkowski  *
513e43ccb0aSPaul Kocialkowski  * +-< XVCLK
514e43ccb0aSPaul Kocialkowski  * |
515e43ccb0aSPaul Kocialkowski  * +-+ pll_pre_div (0x3037 [3:0], special values: 5: 1.5, 7: 2.5)
516e43ccb0aSPaul Kocialkowski  *   |
517e43ccb0aSPaul Kocialkowski  *   +-+ pll_mul (0x3036 [7:0])
518e43ccb0aSPaul Kocialkowski  *     |
519e43ccb0aSPaul Kocialkowski  *     +-+ sys_div (0x3035 [7:4])
520e43ccb0aSPaul Kocialkowski  *       |
521e43ccb0aSPaul Kocialkowski  *       +-+ mipi_div (0x3035 [3:0])
522e43ccb0aSPaul Kocialkowski  *       | |
523e43ccb0aSPaul Kocialkowski  *       | +-> MIPI_SCLK
524e43ccb0aSPaul Kocialkowski  *       | |
525e43ccb0aSPaul Kocialkowski  *       | +-+ mipi_phy_div (2)
526e43ccb0aSPaul Kocialkowski  *       |   |
527e43ccb0aSPaul Kocialkowski  *       |   +-> MIPI_CLK
528e43ccb0aSPaul Kocialkowski  *       |
529e43ccb0aSPaul Kocialkowski  *       +-+ root_div (0x3037 [4])
530e43ccb0aSPaul Kocialkowski  *         |
531e43ccb0aSPaul Kocialkowski  *         +-+ bit_div (0x3034 [3:0], 8 bits: 2, 10 bits: 2.5, other: 1)
532e43ccb0aSPaul Kocialkowski  *           |
533e43ccb0aSPaul Kocialkowski  *           +-+ sclk_div (0x3106 [3:2])
534e43ccb0aSPaul Kocialkowski  *             |
535e43ccb0aSPaul Kocialkowski  *             +-> SCLK
536e43ccb0aSPaul Kocialkowski  *             |
537e43ccb0aSPaul Kocialkowski  *             +-+ mipi_div (0x3035, 1: PCLK = SCLK)
538e43ccb0aSPaul Kocialkowski  *               |
539e43ccb0aSPaul Kocialkowski  *               +-> PCLK
540e43ccb0aSPaul Kocialkowski  */
541e43ccb0aSPaul Kocialkowski 
542e43ccb0aSPaul Kocialkowski struct ov5648_pll1_config {
543e43ccb0aSPaul Kocialkowski 	unsigned int pll_pre_div;
544e43ccb0aSPaul Kocialkowski 	unsigned int pll_mul;
545e43ccb0aSPaul Kocialkowski 	unsigned int sys_div;
546e43ccb0aSPaul Kocialkowski 	unsigned int root_div;
547e43ccb0aSPaul Kocialkowski 	unsigned int sclk_div;
548e43ccb0aSPaul Kocialkowski 	unsigned int mipi_div;
549e43ccb0aSPaul Kocialkowski };
550e43ccb0aSPaul Kocialkowski 
551e43ccb0aSPaul Kocialkowski /*
552e43ccb0aSPaul Kocialkowski  * PLL2 Clock Tree:
553e43ccb0aSPaul Kocialkowski  *
554e43ccb0aSPaul Kocialkowski  * +-< XVCLK
555e43ccb0aSPaul Kocialkowski  * |
556e43ccb0aSPaul Kocialkowski  * +-+ plls_pre_div (0x303d [5:4], special values: 0: 1, 1: 1.5)
557e43ccb0aSPaul Kocialkowski  *   |
558e43ccb0aSPaul Kocialkowski  *   +-+ plls_div_r (0x303d [2])
559e43ccb0aSPaul Kocialkowski  *     |
560e43ccb0aSPaul Kocialkowski  *     +-+ plls_mul (0x303b [4:0])
561e43ccb0aSPaul Kocialkowski  *       |
562e43ccb0aSPaul Kocialkowski  *       +-+ sys_div (0x303c [3:0])
563e43ccb0aSPaul Kocialkowski  *         |
564e43ccb0aSPaul Kocialkowski  *         +-+ sel_div (0x303d [1:0], special values: 0: 1, 3: 2.5)
565e43ccb0aSPaul Kocialkowski  *           |
566e43ccb0aSPaul Kocialkowski  *           +-> ADCLK
567e43ccb0aSPaul Kocialkowski  */
568e43ccb0aSPaul Kocialkowski 
569e43ccb0aSPaul Kocialkowski struct ov5648_pll2_config {
570e43ccb0aSPaul Kocialkowski 	unsigned int plls_pre_div;
571e43ccb0aSPaul Kocialkowski 	unsigned int plls_div_r;
572e43ccb0aSPaul Kocialkowski 	unsigned int plls_mul;
573e43ccb0aSPaul Kocialkowski 	unsigned int sys_div;
574e43ccb0aSPaul Kocialkowski 	unsigned int sel_div;
575e43ccb0aSPaul Kocialkowski };
576e43ccb0aSPaul Kocialkowski 
577e43ccb0aSPaul Kocialkowski /*
578e43ccb0aSPaul Kocialkowski  * General formulas for (array-centered) mode calculation:
579e43ccb0aSPaul Kocialkowski  * - photo_array_width = 2624
580e43ccb0aSPaul Kocialkowski  * - crop_start_x = (photo_array_width - output_size_x) / 2
581e43ccb0aSPaul Kocialkowski  * - crop_end_x = crop_start_x + offset_x + output_size_x - 1
582e43ccb0aSPaul Kocialkowski  *
583e43ccb0aSPaul Kocialkowski  * - photo_array_height = 1956
584e43ccb0aSPaul Kocialkowski  * - crop_start_y = (photo_array_height - output_size_y) / 2
585e43ccb0aSPaul Kocialkowski  * - crop_end_y = crop_start_y + offset_y + output_size_y - 1
586e43ccb0aSPaul Kocialkowski  */
587e43ccb0aSPaul Kocialkowski 
588e43ccb0aSPaul Kocialkowski struct ov5648_mode {
589e43ccb0aSPaul Kocialkowski 	unsigned int crop_start_x;
590e43ccb0aSPaul Kocialkowski 	unsigned int offset_x;
591e43ccb0aSPaul Kocialkowski 	unsigned int output_size_x;
592e43ccb0aSPaul Kocialkowski 	unsigned int crop_end_x;
593e43ccb0aSPaul Kocialkowski 	unsigned int hts;
594e43ccb0aSPaul Kocialkowski 
595e43ccb0aSPaul Kocialkowski 	unsigned int crop_start_y;
596e43ccb0aSPaul Kocialkowski 	unsigned int offset_y;
597e43ccb0aSPaul Kocialkowski 	unsigned int output_size_y;
598e43ccb0aSPaul Kocialkowski 	unsigned int crop_end_y;
599e43ccb0aSPaul Kocialkowski 	unsigned int vts;
600e43ccb0aSPaul Kocialkowski 
601e43ccb0aSPaul Kocialkowski 	bool binning_x;
602e43ccb0aSPaul Kocialkowski 	bool binning_y;
603e43ccb0aSPaul Kocialkowski 
604e43ccb0aSPaul Kocialkowski 	unsigned int inc_x_odd;
605e43ccb0aSPaul Kocialkowski 	unsigned int inc_x_even;
606e43ccb0aSPaul Kocialkowski 	unsigned int inc_y_odd;
607e43ccb0aSPaul Kocialkowski 	unsigned int inc_y_even;
608e43ccb0aSPaul Kocialkowski 
609e43ccb0aSPaul Kocialkowski 	/* 8-bit frame interval followed by 10-bit frame interval. */
610e43ccb0aSPaul Kocialkowski 	struct v4l2_fract frame_interval[2];
611e43ccb0aSPaul Kocialkowski 
612e43ccb0aSPaul Kocialkowski 	/* 8-bit config followed by 10-bit config. */
613e43ccb0aSPaul Kocialkowski 	const struct ov5648_pll1_config *pll1_config[2];
614e43ccb0aSPaul Kocialkowski 	const struct ov5648_pll2_config *pll2_config;
615e43ccb0aSPaul Kocialkowski 
616e43ccb0aSPaul Kocialkowski 	const struct ov5648_register_value *register_values;
617e43ccb0aSPaul Kocialkowski 	unsigned int register_values_count;
618e43ccb0aSPaul Kocialkowski };
619e43ccb0aSPaul Kocialkowski 
620e43ccb0aSPaul Kocialkowski struct ov5648_state {
621e43ccb0aSPaul Kocialkowski 	const struct ov5648_mode *mode;
622e43ccb0aSPaul Kocialkowski 	u32 mbus_code;
623e43ccb0aSPaul Kocialkowski 
624e43ccb0aSPaul Kocialkowski 	bool streaming;
625e43ccb0aSPaul Kocialkowski };
626e43ccb0aSPaul Kocialkowski 
627e43ccb0aSPaul Kocialkowski struct ov5648_ctrls {
628e43ccb0aSPaul Kocialkowski 	struct v4l2_ctrl *exposure_auto;
629e43ccb0aSPaul Kocialkowski 	struct v4l2_ctrl *exposure;
630e43ccb0aSPaul Kocialkowski 
631e43ccb0aSPaul Kocialkowski 	struct v4l2_ctrl *gain_auto;
632e43ccb0aSPaul Kocialkowski 	struct v4l2_ctrl *gain;
633e43ccb0aSPaul Kocialkowski 
634e43ccb0aSPaul Kocialkowski 	struct v4l2_ctrl *white_balance_auto;
635e43ccb0aSPaul Kocialkowski 	struct v4l2_ctrl *red_balance;
636e43ccb0aSPaul Kocialkowski 	struct v4l2_ctrl *blue_balance;
637e43ccb0aSPaul Kocialkowski 
638e43ccb0aSPaul Kocialkowski 	struct v4l2_ctrl *link_freq;
639e43ccb0aSPaul Kocialkowski 	struct v4l2_ctrl *pixel_rate;
640e43ccb0aSPaul Kocialkowski 
641e43ccb0aSPaul Kocialkowski 	struct v4l2_ctrl_handler handler;
642edd4fbffSSakari Ailus };
643e43ccb0aSPaul Kocialkowski 
644e43ccb0aSPaul Kocialkowski struct ov5648_sensor {
645e43ccb0aSPaul Kocialkowski 	struct device *dev;
646e43ccb0aSPaul Kocialkowski 	struct i2c_client *i2c_client;
647e43ccb0aSPaul Kocialkowski 	struct gpio_desc *reset;
648e43ccb0aSPaul Kocialkowski 	struct gpio_desc *powerdown;
649e43ccb0aSPaul Kocialkowski 	struct regulator *avdd;
650e43ccb0aSPaul Kocialkowski 	struct regulator *dvdd;
651e43ccb0aSPaul Kocialkowski 	struct regulator *dovdd;
652e43ccb0aSPaul Kocialkowski 	struct clk *xvclk;
653e43ccb0aSPaul Kocialkowski 
654e43ccb0aSPaul Kocialkowski 	struct v4l2_fwnode_endpoint endpoint;
655e43ccb0aSPaul Kocialkowski 	struct v4l2_subdev subdev;
656e43ccb0aSPaul Kocialkowski 	struct media_pad pad;
657e43ccb0aSPaul Kocialkowski 
658e43ccb0aSPaul Kocialkowski 	struct mutex mutex;
659e43ccb0aSPaul Kocialkowski 
660e43ccb0aSPaul Kocialkowski 	struct ov5648_state state;
661e43ccb0aSPaul Kocialkowski 	struct ov5648_ctrls ctrls;
662e43ccb0aSPaul Kocialkowski };
663e43ccb0aSPaul Kocialkowski 
664e43ccb0aSPaul Kocialkowski /* Static definitions */
665e43ccb0aSPaul Kocialkowski 
666e43ccb0aSPaul Kocialkowski /*
667e43ccb0aSPaul Kocialkowski  * XVCLK = 24 MHz
668e43ccb0aSPaul Kocialkowski  * SCLK  = 84 MHz
669e43ccb0aSPaul Kocialkowski  * PCLK  = 84 MHz
670e43ccb0aSPaul Kocialkowski  */
671e43ccb0aSPaul Kocialkowski static const struct ov5648_pll1_config ov5648_pll1_config_native_8_bits = {
672e43ccb0aSPaul Kocialkowski 	.pll_pre_div	= 3,
673e43ccb0aSPaul Kocialkowski 	.pll_mul	= 84,
674e43ccb0aSPaul Kocialkowski 	.sys_div	= 2,
675e43ccb0aSPaul Kocialkowski 	.root_div	= 1,
676e43ccb0aSPaul Kocialkowski 	.sclk_div	= 1,
677e43ccb0aSPaul Kocialkowski 	.mipi_div	= 1,
678e43ccb0aSPaul Kocialkowski };
679e43ccb0aSPaul Kocialkowski 
680e43ccb0aSPaul Kocialkowski /*
681e43ccb0aSPaul Kocialkowski  * XVCLK = 24 MHz
682e43ccb0aSPaul Kocialkowski  * SCLK  = 84 MHz
683e43ccb0aSPaul Kocialkowski  * PCLK  = 84 MHz
684e43ccb0aSPaul Kocialkowski  */
685e43ccb0aSPaul Kocialkowski static const struct ov5648_pll1_config ov5648_pll1_config_native_10_bits = {
686e43ccb0aSPaul Kocialkowski 	.pll_pre_div	= 3,
687e43ccb0aSPaul Kocialkowski 	.pll_mul	= 105,
688e43ccb0aSPaul Kocialkowski 	.sys_div	= 2,
689e43ccb0aSPaul Kocialkowski 	.root_div	= 1,
690e43ccb0aSPaul Kocialkowski 	.sclk_div	= 1,
691e43ccb0aSPaul Kocialkowski 	.mipi_div	= 1,
692e43ccb0aSPaul Kocialkowski };
693e43ccb0aSPaul Kocialkowski 
694e43ccb0aSPaul Kocialkowski /*
695e43ccb0aSPaul Kocialkowski  * XVCLK = 24 MHz
696e43ccb0aSPaul Kocialkowski  * ADCLK = 200 MHz
697e43ccb0aSPaul Kocialkowski  */
698e43ccb0aSPaul Kocialkowski static const struct ov5648_pll2_config ov5648_pll2_config_native = {
699e43ccb0aSPaul Kocialkowski 	.plls_pre_div	= 3,
700e43ccb0aSPaul Kocialkowski 	.plls_div_r	= 1,
701e43ccb0aSPaul Kocialkowski 	.plls_mul	= 25,
702e43ccb0aSPaul Kocialkowski 	.sys_div	= 1,
703e43ccb0aSPaul Kocialkowski 	.sel_div	= 1,
704e43ccb0aSPaul Kocialkowski };
705e43ccb0aSPaul Kocialkowski 
706e43ccb0aSPaul Kocialkowski static const struct ov5648_mode ov5648_modes[] = {
707e43ccb0aSPaul Kocialkowski 	/* 2592x1944 */
708e43ccb0aSPaul Kocialkowski 	{
709e43ccb0aSPaul Kocialkowski 		/* Horizontal */
710e43ccb0aSPaul Kocialkowski 		.crop_start_x	= 16,
711e43ccb0aSPaul Kocialkowski 		.offset_x	= 0,
712e43ccb0aSPaul Kocialkowski 		.output_size_x	= 2592,
713e43ccb0aSPaul Kocialkowski 		.crop_end_x	= 2607,
714e43ccb0aSPaul Kocialkowski 		.hts		= 2816,
715e43ccb0aSPaul Kocialkowski 
716e43ccb0aSPaul Kocialkowski 		/* Vertical */
717e43ccb0aSPaul Kocialkowski 		.crop_start_y	= 6,
718e43ccb0aSPaul Kocialkowski 		.offset_y	= 0,
719e43ccb0aSPaul Kocialkowski 		.output_size_y	= 1944,
720e43ccb0aSPaul Kocialkowski 		.crop_end_y	= 1949,
721e43ccb0aSPaul Kocialkowski 		.vts		= 1984,
722e43ccb0aSPaul Kocialkowski 
723e43ccb0aSPaul Kocialkowski 		/* Subsample increase */
724e43ccb0aSPaul Kocialkowski 		.inc_x_odd	= 1,
725e43ccb0aSPaul Kocialkowski 		.inc_x_even	= 1,
726e43ccb0aSPaul Kocialkowski 		.inc_y_odd	= 1,
727e43ccb0aSPaul Kocialkowski 		.inc_y_even	= 1,
728e43ccb0aSPaul Kocialkowski 
729e43ccb0aSPaul Kocialkowski 		/* Frame Interval */
730e43ccb0aSPaul Kocialkowski 		.frame_interval	= {
731e43ccb0aSPaul Kocialkowski 			{ 1,	15 },
732e43ccb0aSPaul Kocialkowski 			{ 1,	15 },
733e43ccb0aSPaul Kocialkowski 		},
734e43ccb0aSPaul Kocialkowski 
735e43ccb0aSPaul Kocialkowski 		/* PLL */
736e43ccb0aSPaul Kocialkowski 		.pll1_config	= {
737e43ccb0aSPaul Kocialkowski 			&ov5648_pll1_config_native_8_bits,
738e43ccb0aSPaul Kocialkowski 			&ov5648_pll1_config_native_10_bits,
739e43ccb0aSPaul Kocialkowski 		},
740e43ccb0aSPaul Kocialkowski 		.pll2_config	= &ov5648_pll2_config_native,
741e43ccb0aSPaul Kocialkowski 	},
742e43ccb0aSPaul Kocialkowski 	/* 1600x1200 (UXGA) */
743e43ccb0aSPaul Kocialkowski 	{
744e43ccb0aSPaul Kocialkowski 		/* Horizontal */
745e43ccb0aSPaul Kocialkowski 		.crop_start_x	= 512,
746e43ccb0aSPaul Kocialkowski 		.offset_x	= 0,
747e43ccb0aSPaul Kocialkowski 		.output_size_x	= 1600,
748e43ccb0aSPaul Kocialkowski 		.crop_end_x	= 2111,
749e43ccb0aSPaul Kocialkowski 		.hts		= 2816,
750e43ccb0aSPaul Kocialkowski 
751e43ccb0aSPaul Kocialkowski 		/* Vertical */
752e43ccb0aSPaul Kocialkowski 		.crop_start_y	= 378,
753e43ccb0aSPaul Kocialkowski 		.offset_y	= 0,
754e43ccb0aSPaul Kocialkowski 		.output_size_y	= 1200,
755e43ccb0aSPaul Kocialkowski 		.crop_end_y	= 1577,
756e43ccb0aSPaul Kocialkowski 		.vts		= 1984,
757e43ccb0aSPaul Kocialkowski 
758e43ccb0aSPaul Kocialkowski 		/* Subsample increase */
759e43ccb0aSPaul Kocialkowski 		.inc_x_odd	= 1,
760e43ccb0aSPaul Kocialkowski 		.inc_x_even	= 1,
761e43ccb0aSPaul Kocialkowski 		.inc_y_odd	= 1,
762e43ccb0aSPaul Kocialkowski 		.inc_y_even	= 1,
763e43ccb0aSPaul Kocialkowski 
764e43ccb0aSPaul Kocialkowski 		/* Frame Interval */
765e43ccb0aSPaul Kocialkowski 		.frame_interval	= {
766e43ccb0aSPaul Kocialkowski 			{ 1,	15 },
767e43ccb0aSPaul Kocialkowski 			{ 1,	15 },
768e43ccb0aSPaul Kocialkowski 		},
769e43ccb0aSPaul Kocialkowski 
770e43ccb0aSPaul Kocialkowski 		/* PLL */
771e43ccb0aSPaul Kocialkowski 		.pll1_config	= {
772e43ccb0aSPaul Kocialkowski 			&ov5648_pll1_config_native_8_bits,
773e43ccb0aSPaul Kocialkowski 			&ov5648_pll1_config_native_10_bits,
774e43ccb0aSPaul Kocialkowski 		},
775e43ccb0aSPaul Kocialkowski 		.pll2_config	= &ov5648_pll2_config_native,
776e43ccb0aSPaul Kocialkowski 	},
777e43ccb0aSPaul Kocialkowski 	/* 1920x1080 (Full HD) */
778e43ccb0aSPaul Kocialkowski 	{
779e43ccb0aSPaul Kocialkowski 		/* Horizontal */
780e43ccb0aSPaul Kocialkowski 		.crop_start_x	= 352,
781e43ccb0aSPaul Kocialkowski 		.offset_x	= 0,
782e43ccb0aSPaul Kocialkowski 		.output_size_x	= 1920,
783e43ccb0aSPaul Kocialkowski 		.crop_end_x	= 2271,
784e43ccb0aSPaul Kocialkowski 		.hts		= 2816,
785e43ccb0aSPaul Kocialkowski 
786e43ccb0aSPaul Kocialkowski 		/* Vertical */
787e43ccb0aSPaul Kocialkowski 		.crop_start_y	= 438,
788e43ccb0aSPaul Kocialkowski 		.offset_y	= 0,
789e43ccb0aSPaul Kocialkowski 		.output_size_y	= 1080,
790e43ccb0aSPaul Kocialkowski 		.crop_end_y	= 1517,
791e43ccb0aSPaul Kocialkowski 		.vts		= 1984,
792e43ccb0aSPaul Kocialkowski 
793e43ccb0aSPaul Kocialkowski 		/* Subsample increase */
794e43ccb0aSPaul Kocialkowski 		.inc_x_odd	= 1,
795e43ccb0aSPaul Kocialkowski 		.inc_x_even	= 1,
796e43ccb0aSPaul Kocialkowski 		.inc_y_odd	= 1,
797e43ccb0aSPaul Kocialkowski 		.inc_y_even	= 1,
798e43ccb0aSPaul Kocialkowski 
799e43ccb0aSPaul Kocialkowski 		/* Frame Interval */
800e43ccb0aSPaul Kocialkowski 		.frame_interval	= {
801e43ccb0aSPaul Kocialkowski 			{ 1,	15 },
802e43ccb0aSPaul Kocialkowski 			{ 1,	15 },
803e43ccb0aSPaul Kocialkowski 		},
804e43ccb0aSPaul Kocialkowski 
805e43ccb0aSPaul Kocialkowski 		/* PLL */
806e43ccb0aSPaul Kocialkowski 		.pll1_config	= {
807e43ccb0aSPaul Kocialkowski 			&ov5648_pll1_config_native_8_bits,
808e43ccb0aSPaul Kocialkowski 			&ov5648_pll1_config_native_10_bits,
809e43ccb0aSPaul Kocialkowski 		},
810e43ccb0aSPaul Kocialkowski 		.pll2_config	= &ov5648_pll2_config_native,
811e43ccb0aSPaul Kocialkowski 	},
812e43ccb0aSPaul Kocialkowski 	/* 1280x960 */
813e43ccb0aSPaul Kocialkowski 	{
814e43ccb0aSPaul Kocialkowski 		/* Horizontal */
815e43ccb0aSPaul Kocialkowski 		.crop_start_x	= 16,
816e43ccb0aSPaul Kocialkowski 		.offset_x	= 8,
817e43ccb0aSPaul Kocialkowski 		.output_size_x	= 1280,
818e43ccb0aSPaul Kocialkowski 		.crop_end_x	= 2607,
819e43ccb0aSPaul Kocialkowski 		.hts		= 1912,
820e43ccb0aSPaul Kocialkowski 
821e43ccb0aSPaul Kocialkowski 		/* Vertical */
822e43ccb0aSPaul Kocialkowski 		.crop_start_y	= 6,
823e43ccb0aSPaul Kocialkowski 		.offset_y	= 6,
824e43ccb0aSPaul Kocialkowski 		.output_size_y	= 960,
825e43ccb0aSPaul Kocialkowski 		.crop_end_y	= 1949,
826e43ccb0aSPaul Kocialkowski 		.vts		= 1496,
827e43ccb0aSPaul Kocialkowski 
828e43ccb0aSPaul Kocialkowski 		/* Binning */
829e43ccb0aSPaul Kocialkowski 		.binning_x	= true,
830e43ccb0aSPaul Kocialkowski 
831e43ccb0aSPaul Kocialkowski 		/* Subsample increase */
832e43ccb0aSPaul Kocialkowski 		.inc_x_odd	= 3,
833e43ccb0aSPaul Kocialkowski 		.inc_x_even	= 1,
834e43ccb0aSPaul Kocialkowski 		.inc_y_odd	= 3,
835e43ccb0aSPaul Kocialkowski 		.inc_y_even	= 1,
836e43ccb0aSPaul Kocialkowski 
837e43ccb0aSPaul Kocialkowski 		/* Frame Interval */
838e43ccb0aSPaul Kocialkowski 		.frame_interval	= {
839e43ccb0aSPaul Kocialkowski 			{ 1,	30 },
840e43ccb0aSPaul Kocialkowski 			{ 1,	30 },
841e43ccb0aSPaul Kocialkowski 		},
842e43ccb0aSPaul Kocialkowski 
843e43ccb0aSPaul Kocialkowski 		/* PLL */
844e43ccb0aSPaul Kocialkowski 		.pll1_config	= {
845e43ccb0aSPaul Kocialkowski 			&ov5648_pll1_config_native_8_bits,
846e43ccb0aSPaul Kocialkowski 			&ov5648_pll1_config_native_10_bits,
847e43ccb0aSPaul Kocialkowski 		},
848e43ccb0aSPaul Kocialkowski 		.pll2_config	= &ov5648_pll2_config_native,
849e43ccb0aSPaul Kocialkowski 	},
850e43ccb0aSPaul Kocialkowski 	/* 1280x720 (HD) */
851e43ccb0aSPaul Kocialkowski 	{
852e43ccb0aSPaul Kocialkowski 		/* Horizontal */
853e43ccb0aSPaul Kocialkowski 		.crop_start_x	= 16,
854e43ccb0aSPaul Kocialkowski 		.offset_x	= 8,
855e43ccb0aSPaul Kocialkowski 		.output_size_x	= 1280,
856e43ccb0aSPaul Kocialkowski 		.crop_end_x	= 2607,
857e43ccb0aSPaul Kocialkowski 		.hts		= 1912,
858e43ccb0aSPaul Kocialkowski 
859e43ccb0aSPaul Kocialkowski 		/* Vertical */
860e43ccb0aSPaul Kocialkowski 		.crop_start_y	= 254,
861e43ccb0aSPaul Kocialkowski 		.offset_y	= 2,
862e43ccb0aSPaul Kocialkowski 		.output_size_y	= 720,
863e43ccb0aSPaul Kocialkowski 		.crop_end_y	= 1701,
864e43ccb0aSPaul Kocialkowski 		.vts		= 1496,
865e43ccb0aSPaul Kocialkowski 
866e43ccb0aSPaul Kocialkowski 		/* Binning */
867e43ccb0aSPaul Kocialkowski 		.binning_x	= true,
868e43ccb0aSPaul Kocialkowski 
869e43ccb0aSPaul Kocialkowski 		/* Subsample increase */
870e43ccb0aSPaul Kocialkowski 		.inc_x_odd	= 3,
871e43ccb0aSPaul Kocialkowski 		.inc_x_even	= 1,
872e43ccb0aSPaul Kocialkowski 		.inc_y_odd	= 3,
873e43ccb0aSPaul Kocialkowski 		.inc_y_even	= 1,
874e43ccb0aSPaul Kocialkowski 
875e43ccb0aSPaul Kocialkowski 		/* Frame Interval */
876e43ccb0aSPaul Kocialkowski 		.frame_interval	= {
877e43ccb0aSPaul Kocialkowski 			{ 1,	30 },
878e43ccb0aSPaul Kocialkowski 			{ 1,	30 },
879e43ccb0aSPaul Kocialkowski 		},
880e43ccb0aSPaul Kocialkowski 
881e43ccb0aSPaul Kocialkowski 		/* PLL */
882e43ccb0aSPaul Kocialkowski 		.pll1_config	= {
883e43ccb0aSPaul Kocialkowski 			&ov5648_pll1_config_native_8_bits,
884e43ccb0aSPaul Kocialkowski 			&ov5648_pll1_config_native_10_bits,
885e43ccb0aSPaul Kocialkowski 		},
886e43ccb0aSPaul Kocialkowski 		.pll2_config	= &ov5648_pll2_config_native,
887e43ccb0aSPaul Kocialkowski 	},
888e43ccb0aSPaul Kocialkowski 	/* 640x480 (VGA) */
889e43ccb0aSPaul Kocialkowski 	{
890e43ccb0aSPaul Kocialkowski 		/* Horizontal */
891e43ccb0aSPaul Kocialkowski 		.crop_start_x	= 0,
892e43ccb0aSPaul Kocialkowski 		.offset_x	= 8,
893e43ccb0aSPaul Kocialkowski 		.output_size_x	= 640,
894e43ccb0aSPaul Kocialkowski 		.crop_end_x	= 2623,
895e43ccb0aSPaul Kocialkowski 		.hts		= 1896,
896e43ccb0aSPaul Kocialkowski 
897e43ccb0aSPaul Kocialkowski 		/* Vertical */
898e43ccb0aSPaul Kocialkowski 		.crop_start_y	= 0,
899e43ccb0aSPaul Kocialkowski 		.offset_y	= 2,
900e43ccb0aSPaul Kocialkowski 		.output_size_y	= 480,
901e43ccb0aSPaul Kocialkowski 		.crop_end_y	= 1953,
902e43ccb0aSPaul Kocialkowski 		.vts		= 984,
903e43ccb0aSPaul Kocialkowski 
904e43ccb0aSPaul Kocialkowski 		/* Binning */
905e43ccb0aSPaul Kocialkowski 		.binning_x	= true,
906e43ccb0aSPaul Kocialkowski 
907e43ccb0aSPaul Kocialkowski 		/* Subsample increase */
908e43ccb0aSPaul Kocialkowski 		.inc_x_odd	= 7,
909e43ccb0aSPaul Kocialkowski 		.inc_x_even	= 1,
910e43ccb0aSPaul Kocialkowski 		.inc_y_odd	= 7,
911e43ccb0aSPaul Kocialkowski 		.inc_y_even	= 1,
912e43ccb0aSPaul Kocialkowski 
913e43ccb0aSPaul Kocialkowski 		/* Frame Interval */
914e43ccb0aSPaul Kocialkowski 		.frame_interval	= {
915e43ccb0aSPaul Kocialkowski 			{ 1,	30 },
916e43ccb0aSPaul Kocialkowski 			{ 1,	30 },
917e43ccb0aSPaul Kocialkowski 		},
918e43ccb0aSPaul Kocialkowski 
919e43ccb0aSPaul Kocialkowski 		/* PLL */
920e43ccb0aSPaul Kocialkowski 		.pll1_config	= {
921e43ccb0aSPaul Kocialkowski 			&ov5648_pll1_config_native_8_bits,
922e43ccb0aSPaul Kocialkowski 			&ov5648_pll1_config_native_10_bits,
923e43ccb0aSPaul Kocialkowski 		},
924e43ccb0aSPaul Kocialkowski 		.pll2_config	= &ov5648_pll2_config_native,
925e43ccb0aSPaul Kocialkowski 	},
926e43ccb0aSPaul Kocialkowski };
927e43ccb0aSPaul Kocialkowski 
928e43ccb0aSPaul Kocialkowski static const u32 ov5648_mbus_codes[] = {
929e43ccb0aSPaul Kocialkowski 	MEDIA_BUS_FMT_SBGGR8_1X8,
930e43ccb0aSPaul Kocialkowski 	MEDIA_BUS_FMT_SBGGR10_1X10,
931e43ccb0aSPaul Kocialkowski };
932e43ccb0aSPaul Kocialkowski 
933e43ccb0aSPaul Kocialkowski static const struct ov5648_register_value ov5648_init_sequence[] = {
934e43ccb0aSPaul Kocialkowski 	/* PSRAM */
935e43ccb0aSPaul Kocialkowski 	{ OV5648_PSRAM_CTRL1_REG, 0x0d },
936e43ccb0aSPaul Kocialkowski 	{ OV5648_PSRAM_CTRLF_REG, 0xf5 },
937e43ccb0aSPaul Kocialkowski };
938e43ccb0aSPaul Kocialkowski 
939e43ccb0aSPaul Kocialkowski static const s64 ov5648_link_freq_menu[] = {
940e43ccb0aSPaul Kocialkowski 	210000000,
941e43ccb0aSPaul Kocialkowski 	168000000,
942e43ccb0aSPaul Kocialkowski };
943e43ccb0aSPaul Kocialkowski 
944e43ccb0aSPaul Kocialkowski static const char *const ov5648_test_pattern_menu[] = {
945e43ccb0aSPaul Kocialkowski 	"Disabled",
946e43ccb0aSPaul Kocialkowski 	"Random data",
947e43ccb0aSPaul Kocialkowski 	"Color bars",
948e43ccb0aSPaul Kocialkowski 	"Color bars with rolling bar",
949e43ccb0aSPaul Kocialkowski 	"Color squares",
950e43ccb0aSPaul Kocialkowski 	"Color squares with rolling bar"
951e43ccb0aSPaul Kocialkowski };
952e43ccb0aSPaul Kocialkowski 
953e43ccb0aSPaul Kocialkowski static const u8 ov5648_test_pattern_bits[] = {
954e43ccb0aSPaul Kocialkowski 	0,
955e43ccb0aSPaul Kocialkowski 	OV5648_ISP_CTRL3D_PATTERN_EN | OV5648_ISP_CTRL3D_PATTERN_RANDOM_DATA,
956e43ccb0aSPaul Kocialkowski 	OV5648_ISP_CTRL3D_PATTERN_EN | OV5648_ISP_CTRL3D_PATTERN_COLOR_BARS,
957e43ccb0aSPaul Kocialkowski 	OV5648_ISP_CTRL3D_PATTERN_EN | OV5648_ISP_CTRL3D_ROLLING_BAR_EN |
958e43ccb0aSPaul Kocialkowski 	OV5648_ISP_CTRL3D_PATTERN_COLOR_BARS,
959e43ccb0aSPaul Kocialkowski 	OV5648_ISP_CTRL3D_PATTERN_EN | OV5648_ISP_CTRL3D_PATTERN_COLOR_SQUARES,
960e43ccb0aSPaul Kocialkowski 	OV5648_ISP_CTRL3D_PATTERN_EN | OV5648_ISP_CTRL3D_ROLLING_BAR_EN |
961e43ccb0aSPaul Kocialkowski 	OV5648_ISP_CTRL3D_PATTERN_COLOR_SQUARES,
962e43ccb0aSPaul Kocialkowski };
963e43ccb0aSPaul Kocialkowski 
964e43ccb0aSPaul Kocialkowski /* Input/Output */
965e43ccb0aSPaul Kocialkowski 
ov5648_read(struct ov5648_sensor * sensor,u16 address,u8 * value)966e43ccb0aSPaul Kocialkowski static int ov5648_read(struct ov5648_sensor *sensor, u16 address, u8 *value)
967e43ccb0aSPaul Kocialkowski {
968e43ccb0aSPaul Kocialkowski 	unsigned char data[2] = { address >> 8, address & 0xff };
969e43ccb0aSPaul Kocialkowski 	struct i2c_client *client = sensor->i2c_client;
970e43ccb0aSPaul Kocialkowski 	int ret;
971e43ccb0aSPaul Kocialkowski 
972e43ccb0aSPaul Kocialkowski 	ret = i2c_master_send(client, data, sizeof(data));
973e43ccb0aSPaul Kocialkowski 	if (ret < 0) {
974e43ccb0aSPaul Kocialkowski 		dev_dbg(&client->dev, "i2c send error at address %#04x\n",
975e43ccb0aSPaul Kocialkowski 			address);
976e43ccb0aSPaul Kocialkowski 		return ret;
977e43ccb0aSPaul Kocialkowski 	}
978e43ccb0aSPaul Kocialkowski 
979e43ccb0aSPaul Kocialkowski 	ret = i2c_master_recv(client, value, 1);
980e43ccb0aSPaul Kocialkowski 	if (ret < 0) {
981e43ccb0aSPaul Kocialkowski 		dev_dbg(&client->dev, "i2c recv error at address %#04x\n",
982e43ccb0aSPaul Kocialkowski 			address);
983e43ccb0aSPaul Kocialkowski 		return ret;
984e43ccb0aSPaul Kocialkowski 	}
985e43ccb0aSPaul Kocialkowski 
986e43ccb0aSPaul Kocialkowski 	return 0;
987e43ccb0aSPaul Kocialkowski }
988e43ccb0aSPaul Kocialkowski 
ov5648_write(struct ov5648_sensor * sensor,u16 address,u8 value)989e43ccb0aSPaul Kocialkowski static int ov5648_write(struct ov5648_sensor *sensor, u16 address, u8 value)
990e43ccb0aSPaul Kocialkowski {
991e43ccb0aSPaul Kocialkowski 	unsigned char data[3] = { address >> 8, address & 0xff, value };
992e43ccb0aSPaul Kocialkowski 	struct i2c_client *client = sensor->i2c_client;
993e43ccb0aSPaul Kocialkowski 	int ret;
994e43ccb0aSPaul Kocialkowski 
995e43ccb0aSPaul Kocialkowski 	ret = i2c_master_send(client, data, sizeof(data));
996e43ccb0aSPaul Kocialkowski 	if (ret < 0) {
997e43ccb0aSPaul Kocialkowski 		dev_dbg(&client->dev, "i2c send error at address %#04x\n",
998e43ccb0aSPaul Kocialkowski 			address);
999e43ccb0aSPaul Kocialkowski 		return ret;
1000e43ccb0aSPaul Kocialkowski 	}
1001e43ccb0aSPaul Kocialkowski 
1002e43ccb0aSPaul Kocialkowski 	return 0;
1003e43ccb0aSPaul Kocialkowski }
1004e43ccb0aSPaul Kocialkowski 
ov5648_write_sequence(struct ov5648_sensor * sensor,const struct ov5648_register_value * sequence,unsigned int sequence_count)1005e43ccb0aSPaul Kocialkowski static int ov5648_write_sequence(struct ov5648_sensor *sensor,
1006e43ccb0aSPaul Kocialkowski 				 const struct ov5648_register_value *sequence,
1007e43ccb0aSPaul Kocialkowski 				 unsigned int sequence_count)
1008e43ccb0aSPaul Kocialkowski {
1009e43ccb0aSPaul Kocialkowski 	unsigned int i;
1010e43ccb0aSPaul Kocialkowski 	int ret = 0;
1011e43ccb0aSPaul Kocialkowski 
1012e43ccb0aSPaul Kocialkowski 	for (i = 0; i < sequence_count; i++) {
1013e43ccb0aSPaul Kocialkowski 		ret = ov5648_write(sensor, sequence[i].address,
1014e43ccb0aSPaul Kocialkowski 				   sequence[i].value);
1015e43ccb0aSPaul Kocialkowski 		if (ret)
1016e43ccb0aSPaul Kocialkowski 			break;
1017e43ccb0aSPaul Kocialkowski 
1018e43ccb0aSPaul Kocialkowski 		if (sequence[i].delay_ms)
1019e43ccb0aSPaul Kocialkowski 			msleep(sequence[i].delay_ms);
1020e43ccb0aSPaul Kocialkowski 	}
1021e43ccb0aSPaul Kocialkowski 
1022e43ccb0aSPaul Kocialkowski 	return ret;
1023e43ccb0aSPaul Kocialkowski }
1024e43ccb0aSPaul Kocialkowski 
ov5648_update_bits(struct ov5648_sensor * sensor,u16 address,u8 mask,u8 bits)1025e43ccb0aSPaul Kocialkowski static int ov5648_update_bits(struct ov5648_sensor *sensor, u16 address,
1026e43ccb0aSPaul Kocialkowski 			      u8 mask, u8 bits)
1027e43ccb0aSPaul Kocialkowski {
1028e43ccb0aSPaul Kocialkowski 	u8 value = 0;
1029e43ccb0aSPaul Kocialkowski 	int ret;
1030e43ccb0aSPaul Kocialkowski 
1031e43ccb0aSPaul Kocialkowski 	ret = ov5648_read(sensor, address, &value);
1032e43ccb0aSPaul Kocialkowski 	if (ret)
1033e43ccb0aSPaul Kocialkowski 		return ret;
1034e43ccb0aSPaul Kocialkowski 
1035e43ccb0aSPaul Kocialkowski 	value &= ~mask;
1036e43ccb0aSPaul Kocialkowski 	value |= bits;
1037e43ccb0aSPaul Kocialkowski 
1038e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, address, value);
1039e43ccb0aSPaul Kocialkowski 	if (ret)
1040e43ccb0aSPaul Kocialkowski 		return ret;
1041e43ccb0aSPaul Kocialkowski 
1042e43ccb0aSPaul Kocialkowski 	return 0;
1043e43ccb0aSPaul Kocialkowski }
1044e43ccb0aSPaul Kocialkowski 
1045e43ccb0aSPaul Kocialkowski /* Sensor */
1046e43ccb0aSPaul Kocialkowski 
ov5648_sw_reset(struct ov5648_sensor * sensor)1047e43ccb0aSPaul Kocialkowski static int ov5648_sw_reset(struct ov5648_sensor *sensor)
1048e43ccb0aSPaul Kocialkowski {
1049e43ccb0aSPaul Kocialkowski 	return ov5648_write(sensor, OV5648_SW_RESET_REG, OV5648_SW_RESET_RESET);
1050e43ccb0aSPaul Kocialkowski }
1051e43ccb0aSPaul Kocialkowski 
ov5648_sw_standby(struct ov5648_sensor * sensor,int standby)1052e43ccb0aSPaul Kocialkowski static int ov5648_sw_standby(struct ov5648_sensor *sensor, int standby)
1053e43ccb0aSPaul Kocialkowski {
1054e43ccb0aSPaul Kocialkowski 	u8 value = 0;
1055e43ccb0aSPaul Kocialkowski 
1056e43ccb0aSPaul Kocialkowski 	if (!standby)
1057e43ccb0aSPaul Kocialkowski 		value = OV5648_SW_STANDBY_STREAM_ON;
1058e43ccb0aSPaul Kocialkowski 
1059e43ccb0aSPaul Kocialkowski 	return ov5648_write(sensor, OV5648_SW_STANDBY_REG, value);
1060e43ccb0aSPaul Kocialkowski }
1061e43ccb0aSPaul Kocialkowski 
ov5648_chip_id_check(struct ov5648_sensor * sensor)1062e43ccb0aSPaul Kocialkowski static int ov5648_chip_id_check(struct ov5648_sensor *sensor)
1063e43ccb0aSPaul Kocialkowski {
1064e43ccb0aSPaul Kocialkowski 	u16 regs[] = { OV5648_CHIP_ID_H_REG, OV5648_CHIP_ID_L_REG };
1065e43ccb0aSPaul Kocialkowski 	u8 values[] = { OV5648_CHIP_ID_H_VALUE, OV5648_CHIP_ID_L_VALUE };
1066e43ccb0aSPaul Kocialkowski 	unsigned int i;
1067e43ccb0aSPaul Kocialkowski 	u8 value;
1068e43ccb0aSPaul Kocialkowski 	int ret;
1069e43ccb0aSPaul Kocialkowski 
1070e43ccb0aSPaul Kocialkowski 	for (i = 0; i < ARRAY_SIZE(regs); i++) {
1071e43ccb0aSPaul Kocialkowski 		ret = ov5648_read(sensor, regs[i], &value);
1072e43ccb0aSPaul Kocialkowski 		if (ret < 0)
1073e43ccb0aSPaul Kocialkowski 			return ret;
1074e43ccb0aSPaul Kocialkowski 
1075e43ccb0aSPaul Kocialkowski 		if (value != values[i]) {
1076e43ccb0aSPaul Kocialkowski 			dev_err(sensor->dev,
1077e43ccb0aSPaul Kocialkowski 				"chip id value mismatch: %#x instead of %#x\n",
1078e43ccb0aSPaul Kocialkowski 				value, values[i]);
1079e43ccb0aSPaul Kocialkowski 			return -EINVAL;
1080e43ccb0aSPaul Kocialkowski 		}
1081e43ccb0aSPaul Kocialkowski 	}
1082e43ccb0aSPaul Kocialkowski 
1083e43ccb0aSPaul Kocialkowski 	return 0;
1084e43ccb0aSPaul Kocialkowski }
1085e43ccb0aSPaul Kocialkowski 
ov5648_avdd_internal_power(struct ov5648_sensor * sensor,int on)1086e43ccb0aSPaul Kocialkowski static int ov5648_avdd_internal_power(struct ov5648_sensor *sensor, int on)
1087e43ccb0aSPaul Kocialkowski {
1088e43ccb0aSPaul Kocialkowski 	return ov5648_write(sensor, OV5648_A_PWC_PK_O0_REG,
1089e43ccb0aSPaul Kocialkowski 			    on ? 0 : OV5648_A_PWC_PK_O0_BP_REGULATOR_N);
1090e43ccb0aSPaul Kocialkowski }
1091e43ccb0aSPaul Kocialkowski 
ov5648_pad_configure(struct ov5648_sensor * sensor)1092e43ccb0aSPaul Kocialkowski static int ov5648_pad_configure(struct ov5648_sensor *sensor)
1093e43ccb0aSPaul Kocialkowski {
1094e43ccb0aSPaul Kocialkowski 	int ret;
1095e43ccb0aSPaul Kocialkowski 
1096e43ccb0aSPaul Kocialkowski 	/* Configure pads as input. */
1097e43ccb0aSPaul Kocialkowski 
1098e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_PAD_OEN1_REG, 0);
1099e43ccb0aSPaul Kocialkowski 	if (ret)
1100e43ccb0aSPaul Kocialkowski 		return ret;
1101e43ccb0aSPaul Kocialkowski 
1102e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_PAD_OEN2_REG, 0);
1103e43ccb0aSPaul Kocialkowski 	if (ret)
1104e43ccb0aSPaul Kocialkowski 		return ret;
1105e43ccb0aSPaul Kocialkowski 
1106e43ccb0aSPaul Kocialkowski 	/* Disable FREX pin. */
1107e43ccb0aSPaul Kocialkowski 
1108e43ccb0aSPaul Kocialkowski 	return ov5648_write(sensor, OV5648_PAD_PK_REG,
1109e43ccb0aSPaul Kocialkowski 			    OV5648_PAD_PK_DRIVE_STRENGTH_1X |
1110e43ccb0aSPaul Kocialkowski 			    OV5648_PAD_PK_FREX_N);
1111e43ccb0aSPaul Kocialkowski }
1112e43ccb0aSPaul Kocialkowski 
ov5648_mipi_configure(struct ov5648_sensor * sensor)1113e43ccb0aSPaul Kocialkowski static int ov5648_mipi_configure(struct ov5648_sensor *sensor)
1114e43ccb0aSPaul Kocialkowski {
111594d964e5SLaurent Pinchart 	struct v4l2_mbus_config_mipi_csi2 *bus_mipi_csi2 =
1116e43ccb0aSPaul Kocialkowski 		&sensor->endpoint.bus.mipi_csi2;
1117e43ccb0aSPaul Kocialkowski 	unsigned int lanes_count = bus_mipi_csi2->num_data_lanes;
1118e43ccb0aSPaul Kocialkowski 	int ret;
1119e43ccb0aSPaul Kocialkowski 
1120e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_MIPI_CTRL0_REG,
1121e43ccb0aSPaul Kocialkowski 			   OV5648_MIPI_CTRL0_CLK_LANE_AUTOGATE |
1122e43ccb0aSPaul Kocialkowski 			   OV5648_MIPI_CTRL0_LANE_SELECT_LANE1 |
1123e43ccb0aSPaul Kocialkowski 			   OV5648_MIPI_CTRL0_IDLE_LP11);
1124e43ccb0aSPaul Kocialkowski 	if (ret)
1125e43ccb0aSPaul Kocialkowski 		return ret;
1126e43ccb0aSPaul Kocialkowski 
1127e43ccb0aSPaul Kocialkowski 	return ov5648_write(sensor, OV5648_MIPI_SC_CTRL0_REG,
1128e43ccb0aSPaul Kocialkowski 			    OV5648_MIPI_SC_CTRL0_MIPI_LANES(lanes_count) |
1129e43ccb0aSPaul Kocialkowski 			    OV5648_MIPI_SC_CTRL0_PHY_LP_RX_PD |
1130e43ccb0aSPaul Kocialkowski 			    OV5648_MIPI_SC_CTRL0_MIPI_EN);
1131e43ccb0aSPaul Kocialkowski }
1132e43ccb0aSPaul Kocialkowski 
ov5648_black_level_configure(struct ov5648_sensor * sensor)1133e43ccb0aSPaul Kocialkowski static int ov5648_black_level_configure(struct ov5648_sensor *sensor)
1134e43ccb0aSPaul Kocialkowski {
1135e43ccb0aSPaul Kocialkowski 	int ret;
1136e43ccb0aSPaul Kocialkowski 
1137e43ccb0aSPaul Kocialkowski 	/* Up to 6 lines are available for black level calibration. */
1138e43ccb0aSPaul Kocialkowski 
1139e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_BLC_CTRL1_REG,
1140e43ccb0aSPaul Kocialkowski 			   OV5648_BLC_CTRL1_START_LINE(2));
1141e43ccb0aSPaul Kocialkowski 	if (ret)
1142e43ccb0aSPaul Kocialkowski 		return ret;
1143e43ccb0aSPaul Kocialkowski 
1144e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_BLC_CTRL2_REG,
1145e43ccb0aSPaul Kocialkowski 			   OV5648_BLC_CTRL2_AUTO_EN |
1146e43ccb0aSPaul Kocialkowski 			   OV5648_BLC_CTRL2_RESET_FRAME_NUM(5));
1147e43ccb0aSPaul Kocialkowski 	if (ret)
1148e43ccb0aSPaul Kocialkowski 		return ret;
1149e43ccb0aSPaul Kocialkowski 
1150e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_BLC_LINE_NUM_REG,
1151e43ccb0aSPaul Kocialkowski 			   OV5648_BLC_LINE_NUM(4));
1152e43ccb0aSPaul Kocialkowski 	if (ret)
1153e43ccb0aSPaul Kocialkowski 		return ret;
1154e43ccb0aSPaul Kocialkowski 
1155e43ccb0aSPaul Kocialkowski 	return ov5648_update_bits(sensor, OV5648_BLC_CTRL5_REG,
1156e43ccb0aSPaul Kocialkowski 				  OV5648_BLC_CTRL5_UPDATE_EN,
1157e43ccb0aSPaul Kocialkowski 				  OV5648_BLC_CTRL5_UPDATE_EN);
1158e43ccb0aSPaul Kocialkowski }
1159e43ccb0aSPaul Kocialkowski 
ov5648_isp_configure(struct ov5648_sensor * sensor)1160e43ccb0aSPaul Kocialkowski static int ov5648_isp_configure(struct ov5648_sensor *sensor)
1161e43ccb0aSPaul Kocialkowski {
1162e43ccb0aSPaul Kocialkowski 	u8 bits;
1163e43ccb0aSPaul Kocialkowski 	int ret;
1164e43ccb0aSPaul Kocialkowski 
1165e43ccb0aSPaul Kocialkowski 	/* Enable black and white level correction. */
1166e43ccb0aSPaul Kocialkowski 	bits = OV5648_ISP_CTRL0_BLACK_CORRECT_EN |
1167e43ccb0aSPaul Kocialkowski 	       OV5648_ISP_CTRL0_WHITE_CORRECT_EN;
1168e43ccb0aSPaul Kocialkowski 
1169e43ccb0aSPaul Kocialkowski 	ret = ov5648_update_bits(sensor, OV5648_ISP_CTRL0_REG, bits, bits);
1170e43ccb0aSPaul Kocialkowski 	if (ret)
1171e43ccb0aSPaul Kocialkowski 		return ret;
1172e43ccb0aSPaul Kocialkowski 
1173e43ccb0aSPaul Kocialkowski 	/* Enable AWB. */
1174e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_ISP_CTRL1_REG,
1175e43ccb0aSPaul Kocialkowski 			   OV5648_ISP_CTRL1_AWB_EN);
1176e43ccb0aSPaul Kocialkowski 	if (ret)
1177e43ccb0aSPaul Kocialkowski 		return ret;
1178e43ccb0aSPaul Kocialkowski 
1179e43ccb0aSPaul Kocialkowski 	/* Enable AWB gain and windowing. */
1180e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_ISP_CTRL2_REG,
1181e43ccb0aSPaul Kocialkowski 			   OV5648_ISP_CTRL2_WIN_EN |
1182e43ccb0aSPaul Kocialkowski 			   OV5648_ISP_CTRL2_AWB_GAIN_EN);
1183e43ccb0aSPaul Kocialkowski 	if (ret)
1184e43ccb0aSPaul Kocialkowski 		return ret;
1185e43ccb0aSPaul Kocialkowski 
1186e43ccb0aSPaul Kocialkowski 	/* Enable buffering and auto-binning. */
1187e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_ISP_CTRL3_REG,
1188e43ccb0aSPaul Kocialkowski 			   OV5648_ISP_CTRL3_BUF_EN |
1189e43ccb0aSPaul Kocialkowski 			   OV5648_ISP_CTRL3_BIN_AUTO_EN);
1190e43ccb0aSPaul Kocialkowski 	if (ret)
1191e43ccb0aSPaul Kocialkowski 		return ret;
1192e43ccb0aSPaul Kocialkowski 
1193e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_ISP_CTRL4_REG, 0);
1194e43ccb0aSPaul Kocialkowski 	if (ret)
1195e43ccb0aSPaul Kocialkowski 		return ret;
1196e43ccb0aSPaul Kocialkowski 
1197e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_ISP_CTRL1F_REG,
1198e43ccb0aSPaul Kocialkowski 			   OV5648_ISP_CTRL1F_OUTPUT_EN);
1199e43ccb0aSPaul Kocialkowski 	if (ret)
1200e43ccb0aSPaul Kocialkowski 		return ret;
1201e43ccb0aSPaul Kocialkowski 
1202e43ccb0aSPaul Kocialkowski 	/* Enable post-binning filters. */
1203e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_ISP_CTRL4B_REG,
1204e43ccb0aSPaul Kocialkowski 			   OV5648_ISP_CTRL4B_POST_BIN_H_EN |
1205e43ccb0aSPaul Kocialkowski 			   OV5648_ISP_CTRL4B_POST_BIN_V_EN);
1206e43ccb0aSPaul Kocialkowski 	if (ret)
1207e43ccb0aSPaul Kocialkowski 		return ret;
1208e43ccb0aSPaul Kocialkowski 
1209e43ccb0aSPaul Kocialkowski 	/* Disable debanding and night mode. Debug bit seems necessary. */
1210e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_AEC_CTRL0_REG,
1211e43ccb0aSPaul Kocialkowski 			   OV5648_AEC_CTRL0_DEBUG |
1212e43ccb0aSPaul Kocialkowski 			   OV5648_AEC_CTRL0_START_SEL_EN);
1213e43ccb0aSPaul Kocialkowski 	if (ret)
1214e43ccb0aSPaul Kocialkowski 		return ret;
1215e43ccb0aSPaul Kocialkowski 
1216e43ccb0aSPaul Kocialkowski 	return ov5648_write(sensor, OV5648_MANUAL_CTRL_REG,
1217e43ccb0aSPaul Kocialkowski 			    OV5648_MANUAL_CTRL_FRAME_DELAY(1));
1218e43ccb0aSPaul Kocialkowski }
1219e43ccb0aSPaul Kocialkowski 
ov5648_mode_pll1_rate(struct ov5648_sensor * sensor,const struct ov5648_pll1_config * config)1220e43ccb0aSPaul Kocialkowski static unsigned long ov5648_mode_pll1_rate(struct ov5648_sensor *sensor,
1221e43ccb0aSPaul Kocialkowski 					   const struct ov5648_pll1_config *config)
1222e43ccb0aSPaul Kocialkowski {
1223e43ccb0aSPaul Kocialkowski 	unsigned long xvclk_rate;
1224e43ccb0aSPaul Kocialkowski 	unsigned long pll1_rate;
1225e43ccb0aSPaul Kocialkowski 
1226e43ccb0aSPaul Kocialkowski 	xvclk_rate = clk_get_rate(sensor->xvclk);
1227e43ccb0aSPaul Kocialkowski 	pll1_rate = xvclk_rate * config->pll_mul;
1228e43ccb0aSPaul Kocialkowski 
1229e43ccb0aSPaul Kocialkowski 	switch (config->pll_pre_div) {
1230e43ccb0aSPaul Kocialkowski 	case 5:
1231e43ccb0aSPaul Kocialkowski 		pll1_rate *= 3;
1232e43ccb0aSPaul Kocialkowski 		pll1_rate /= 2;
1233e43ccb0aSPaul Kocialkowski 		break;
1234e43ccb0aSPaul Kocialkowski 	case 7:
1235e43ccb0aSPaul Kocialkowski 		pll1_rate *= 5;
1236e43ccb0aSPaul Kocialkowski 		pll1_rate /= 2;
1237e43ccb0aSPaul Kocialkowski 		break;
1238e43ccb0aSPaul Kocialkowski 	default:
1239e43ccb0aSPaul Kocialkowski 		pll1_rate /= config->pll_pre_div;
1240e43ccb0aSPaul Kocialkowski 		break;
1241e43ccb0aSPaul Kocialkowski 	}
1242e43ccb0aSPaul Kocialkowski 
1243e43ccb0aSPaul Kocialkowski 	return pll1_rate;
1244e43ccb0aSPaul Kocialkowski }
1245e43ccb0aSPaul Kocialkowski 
ov5648_mode_pll1_configure(struct ov5648_sensor * sensor,const struct ov5648_mode * mode,u32 mbus_code)1246e43ccb0aSPaul Kocialkowski static int ov5648_mode_pll1_configure(struct ov5648_sensor *sensor,
1247e43ccb0aSPaul Kocialkowski 				      const struct ov5648_mode *mode,
1248e43ccb0aSPaul Kocialkowski 				      u32 mbus_code)
1249e43ccb0aSPaul Kocialkowski {
1250e43ccb0aSPaul Kocialkowski 	const struct ov5648_pll1_config *config;
1251e43ccb0aSPaul Kocialkowski 	u8 value;
1252e43ccb0aSPaul Kocialkowski 	int ret;
1253e43ccb0aSPaul Kocialkowski 
1254e43ccb0aSPaul Kocialkowski 	value = OV5648_PLL_CTRL0_PLL_CHARGE_PUMP(1);
1255e43ccb0aSPaul Kocialkowski 
1256e43ccb0aSPaul Kocialkowski 	switch (mbus_code) {
1257e43ccb0aSPaul Kocialkowski 	case MEDIA_BUS_FMT_SBGGR8_1X8:
1258e43ccb0aSPaul Kocialkowski 		config = mode->pll1_config[0];
1259e43ccb0aSPaul Kocialkowski 		value |= OV5648_PLL_CTRL0_BITS(8);
1260e43ccb0aSPaul Kocialkowski 		break;
1261e43ccb0aSPaul Kocialkowski 	case MEDIA_BUS_FMT_SBGGR10_1X10:
1262e43ccb0aSPaul Kocialkowski 		config = mode->pll1_config[1];
1263e43ccb0aSPaul Kocialkowski 		value |= OV5648_PLL_CTRL0_BITS(10);
1264e43ccb0aSPaul Kocialkowski 		break;
1265e43ccb0aSPaul Kocialkowski 	default:
1266e43ccb0aSPaul Kocialkowski 		return -EINVAL;
1267e43ccb0aSPaul Kocialkowski 	}
1268e43ccb0aSPaul Kocialkowski 
1269e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_PLL_CTRL0_REG, value);
1270e43ccb0aSPaul Kocialkowski 	if (ret)
1271e43ccb0aSPaul Kocialkowski 		return ret;
1272e43ccb0aSPaul Kocialkowski 
1273e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_PLL_DIV_REG,
1274e43ccb0aSPaul Kocialkowski 			   OV5648_PLL_DIV_ROOT_DIV(config->root_div) |
1275e43ccb0aSPaul Kocialkowski 			   OV5648_PLL_DIV_PLL_PRE_DIV(config->pll_pre_div));
1276e43ccb0aSPaul Kocialkowski 	if (ret)
1277e43ccb0aSPaul Kocialkowski 		return ret;
1278e43ccb0aSPaul Kocialkowski 
1279e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_PLL_MUL_REG,
1280e43ccb0aSPaul Kocialkowski 			   OV5648_PLL_MUL(config->pll_mul));
1281e43ccb0aSPaul Kocialkowski 	if (ret)
1282e43ccb0aSPaul Kocialkowski 		return ret;
1283e43ccb0aSPaul Kocialkowski 
1284e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_PLL_CTRL1_REG,
1285e43ccb0aSPaul Kocialkowski 			   OV5648_PLL_CTRL1_SYS_DIV(config->sys_div) |
1286e43ccb0aSPaul Kocialkowski 			   OV5648_PLL_CTRL1_MIPI_DIV(config->mipi_div));
1287e43ccb0aSPaul Kocialkowski 	if (ret)
1288e43ccb0aSPaul Kocialkowski 		return ret;
1289e43ccb0aSPaul Kocialkowski 
1290e43ccb0aSPaul Kocialkowski 	return ov5648_write(sensor, OV5648_SRB_CTRL_REG,
1291e43ccb0aSPaul Kocialkowski 			    OV5648_SRB_CTRL_SCLK_DIV(config->sclk_div) |
1292e43ccb0aSPaul Kocialkowski 			    OV5648_SRB_CTRL_SCLK_ARBITER_EN);
1293e43ccb0aSPaul Kocialkowski }
1294e43ccb0aSPaul Kocialkowski 
ov5648_mode_pll2_configure(struct ov5648_sensor * sensor,const struct ov5648_mode * mode)1295e43ccb0aSPaul Kocialkowski static int ov5648_mode_pll2_configure(struct ov5648_sensor *sensor,
1296e43ccb0aSPaul Kocialkowski 				      const struct ov5648_mode *mode)
1297e43ccb0aSPaul Kocialkowski {
1298e43ccb0aSPaul Kocialkowski 	const struct ov5648_pll2_config *config = mode->pll2_config;
1299e43ccb0aSPaul Kocialkowski 	int ret;
1300e43ccb0aSPaul Kocialkowski 
1301e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_PLLS_DIV_REG,
1302e43ccb0aSPaul Kocialkowski 			   OV5648_PLLS_DIV_PLLS_PRE_DIV(config->plls_pre_div) |
1303e43ccb0aSPaul Kocialkowski 			   OV5648_PLLS_DIV_PLLS_DIV_R(config->plls_div_r) |
1304e43ccb0aSPaul Kocialkowski 			   OV5648_PLLS_DIV_PLLS_SEL_DIV(config->sel_div));
1305e43ccb0aSPaul Kocialkowski 	if (ret)
1306e43ccb0aSPaul Kocialkowski 		return ret;
1307e43ccb0aSPaul Kocialkowski 
1308e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_PLLS_MUL_REG,
1309e43ccb0aSPaul Kocialkowski 			   OV5648_PLLS_MUL(config->plls_mul));
1310e43ccb0aSPaul Kocialkowski 	if (ret)
1311e43ccb0aSPaul Kocialkowski 		return ret;
1312e43ccb0aSPaul Kocialkowski 
1313e43ccb0aSPaul Kocialkowski 	return ov5648_write(sensor, OV5648_PLLS_CTRL_REG,
1314e43ccb0aSPaul Kocialkowski 			    OV5648_PLLS_CTRL_PLL_CHARGE_PUMP(1) |
1315e43ccb0aSPaul Kocialkowski 			    OV5648_PLLS_CTRL_SYS_DIV(config->sys_div));
1316e43ccb0aSPaul Kocialkowski }
1317e43ccb0aSPaul Kocialkowski 
ov5648_mode_configure(struct ov5648_sensor * sensor,const struct ov5648_mode * mode,u32 mbus_code)1318e43ccb0aSPaul Kocialkowski static int ov5648_mode_configure(struct ov5648_sensor *sensor,
1319e43ccb0aSPaul Kocialkowski 				 const struct ov5648_mode *mode, u32 mbus_code)
1320e43ccb0aSPaul Kocialkowski {
1321e43ccb0aSPaul Kocialkowski 	int ret;
1322e43ccb0aSPaul Kocialkowski 
1323e43ccb0aSPaul Kocialkowski 	/* Crop Start X */
1324e43ccb0aSPaul Kocialkowski 
1325e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_CROP_START_X_H_REG,
1326e43ccb0aSPaul Kocialkowski 			   OV5648_CROP_START_X_H(mode->crop_start_x));
1327e43ccb0aSPaul Kocialkowski 	if (ret)
1328e43ccb0aSPaul Kocialkowski 		return ret;
1329e43ccb0aSPaul Kocialkowski 
1330e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_CROP_START_X_L_REG,
1331e43ccb0aSPaul Kocialkowski 			   OV5648_CROP_START_X_L(mode->crop_start_x));
1332e43ccb0aSPaul Kocialkowski 	if (ret)
1333e43ccb0aSPaul Kocialkowski 		return ret;
1334e43ccb0aSPaul Kocialkowski 
1335e43ccb0aSPaul Kocialkowski 	/* Offset X */
1336e43ccb0aSPaul Kocialkowski 
1337e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_OFFSET_X_H_REG,
1338e43ccb0aSPaul Kocialkowski 			   OV5648_OFFSET_X_H(mode->offset_x));
1339e43ccb0aSPaul Kocialkowski 	if (ret)
1340e43ccb0aSPaul Kocialkowski 		return ret;
1341e43ccb0aSPaul Kocialkowski 
1342e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_OFFSET_X_L_REG,
1343e43ccb0aSPaul Kocialkowski 			   OV5648_OFFSET_X_L(mode->offset_x));
1344e43ccb0aSPaul Kocialkowski 	if (ret)
1345e43ccb0aSPaul Kocialkowski 		return ret;
1346e43ccb0aSPaul Kocialkowski 
1347e43ccb0aSPaul Kocialkowski 	/* Output Size X */
1348e43ccb0aSPaul Kocialkowski 
1349e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_OUTPUT_SIZE_X_H_REG,
1350e43ccb0aSPaul Kocialkowski 			   OV5648_OUTPUT_SIZE_X_H(mode->output_size_x));
1351e43ccb0aSPaul Kocialkowski 	if (ret)
1352e43ccb0aSPaul Kocialkowski 		return ret;
1353e43ccb0aSPaul Kocialkowski 
1354e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_OUTPUT_SIZE_X_L_REG,
1355e43ccb0aSPaul Kocialkowski 			   OV5648_OUTPUT_SIZE_X_L(mode->output_size_x));
1356e43ccb0aSPaul Kocialkowski 	if (ret)
1357e43ccb0aSPaul Kocialkowski 		return ret;
1358e43ccb0aSPaul Kocialkowski 
1359e43ccb0aSPaul Kocialkowski 	/* Crop End X */
1360e43ccb0aSPaul Kocialkowski 
1361e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_CROP_END_X_H_REG,
1362e43ccb0aSPaul Kocialkowski 			   OV5648_CROP_END_X_H(mode->crop_end_x));
1363e43ccb0aSPaul Kocialkowski 	if (ret)
1364e43ccb0aSPaul Kocialkowski 		return ret;
1365e43ccb0aSPaul Kocialkowski 
1366e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_CROP_END_X_L_REG,
1367e43ccb0aSPaul Kocialkowski 			   OV5648_CROP_END_X_L(mode->crop_end_x));
1368e43ccb0aSPaul Kocialkowski 	if (ret)
1369e43ccb0aSPaul Kocialkowski 		return ret;
1370e43ccb0aSPaul Kocialkowski 
1371e43ccb0aSPaul Kocialkowski 	/* Horizontal Total Size */
1372e43ccb0aSPaul Kocialkowski 
1373e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_HTS_H_REG, OV5648_HTS_H(mode->hts));
1374e43ccb0aSPaul Kocialkowski 	if (ret)
1375e43ccb0aSPaul Kocialkowski 		return ret;
1376e43ccb0aSPaul Kocialkowski 
1377e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_HTS_L_REG, OV5648_HTS_L(mode->hts));
1378e43ccb0aSPaul Kocialkowski 	if (ret)
1379e43ccb0aSPaul Kocialkowski 		return ret;
1380e43ccb0aSPaul Kocialkowski 
1381e43ccb0aSPaul Kocialkowski 	/* Crop Start Y */
1382e43ccb0aSPaul Kocialkowski 
1383e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_CROP_START_Y_H_REG,
1384e43ccb0aSPaul Kocialkowski 			   OV5648_CROP_START_Y_H(mode->crop_start_y));
1385e43ccb0aSPaul Kocialkowski 	if (ret)
1386e43ccb0aSPaul Kocialkowski 		return ret;
1387e43ccb0aSPaul Kocialkowski 
1388e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_CROP_START_Y_L_REG,
1389e43ccb0aSPaul Kocialkowski 			   OV5648_CROP_START_Y_L(mode->crop_start_y));
1390e43ccb0aSPaul Kocialkowski 	if (ret)
1391e43ccb0aSPaul Kocialkowski 		return ret;
1392e43ccb0aSPaul Kocialkowski 
1393e43ccb0aSPaul Kocialkowski 	/* Offset Y */
1394e43ccb0aSPaul Kocialkowski 
1395e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_OFFSET_Y_H_REG,
1396e43ccb0aSPaul Kocialkowski 			   OV5648_OFFSET_Y_H(mode->offset_y));
1397e43ccb0aSPaul Kocialkowski 	if (ret)
1398e43ccb0aSPaul Kocialkowski 		return ret;
1399e43ccb0aSPaul Kocialkowski 
1400e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_OFFSET_Y_L_REG,
1401e43ccb0aSPaul Kocialkowski 			   OV5648_OFFSET_Y_L(mode->offset_y));
1402e43ccb0aSPaul Kocialkowski 	if (ret)
1403e43ccb0aSPaul Kocialkowski 		return ret;
1404e43ccb0aSPaul Kocialkowski 
1405e43ccb0aSPaul Kocialkowski 	/* Output Size Y */
1406e43ccb0aSPaul Kocialkowski 
1407e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_OUTPUT_SIZE_Y_H_REG,
1408e43ccb0aSPaul Kocialkowski 			   OV5648_OUTPUT_SIZE_Y_H(mode->output_size_y));
1409e43ccb0aSPaul Kocialkowski 	if (ret)
1410e43ccb0aSPaul Kocialkowski 		return ret;
1411e43ccb0aSPaul Kocialkowski 
1412e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_OUTPUT_SIZE_Y_L_REG,
1413e43ccb0aSPaul Kocialkowski 			   OV5648_OUTPUT_SIZE_Y_L(mode->output_size_y));
1414e43ccb0aSPaul Kocialkowski 	if (ret)
1415e43ccb0aSPaul Kocialkowski 		return ret;
1416e43ccb0aSPaul Kocialkowski 
1417e43ccb0aSPaul Kocialkowski 	/* Crop End Y */
1418e43ccb0aSPaul Kocialkowski 
1419e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_CROP_END_Y_H_REG,
1420e43ccb0aSPaul Kocialkowski 			   OV5648_CROP_END_Y_H(mode->crop_end_y));
1421e43ccb0aSPaul Kocialkowski 	if (ret)
1422e43ccb0aSPaul Kocialkowski 		return ret;
1423e43ccb0aSPaul Kocialkowski 
1424e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_CROP_END_Y_L_REG,
1425e43ccb0aSPaul Kocialkowski 			   OV5648_CROP_END_Y_L(mode->crop_end_y));
1426e43ccb0aSPaul Kocialkowski 	if (ret)
1427e43ccb0aSPaul Kocialkowski 		return ret;
1428e43ccb0aSPaul Kocialkowski 
1429e43ccb0aSPaul Kocialkowski 	/* Vertical Total Size */
1430e43ccb0aSPaul Kocialkowski 
1431e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_VTS_H_REG, OV5648_VTS_H(mode->vts));
1432e43ccb0aSPaul Kocialkowski 	if (ret)
1433e43ccb0aSPaul Kocialkowski 		return ret;
1434e43ccb0aSPaul Kocialkowski 
1435e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_VTS_L_REG, OV5648_VTS_L(mode->vts));
1436e43ccb0aSPaul Kocialkowski 	if (ret)
1437e43ccb0aSPaul Kocialkowski 		return ret;
1438e43ccb0aSPaul Kocialkowski 
1439e43ccb0aSPaul Kocialkowski 	/* Flip/Mirror/Binning */
1440e43ccb0aSPaul Kocialkowski 
1441e43ccb0aSPaul Kocialkowski 	/*
1442e43ccb0aSPaul Kocialkowski 	 * A debug bit is enabled by default and needs to be cleared for
1443e43ccb0aSPaul Kocialkowski 	 * subsampling to work.
1444e43ccb0aSPaul Kocialkowski 	 */
1445e43ccb0aSPaul Kocialkowski 	ret = ov5648_update_bits(sensor, OV5648_TC20_REG,
1446e43ccb0aSPaul Kocialkowski 				 OV5648_TC20_DEBUG |
1447e43ccb0aSPaul Kocialkowski 				 OV5648_TC20_BINNING_VERT_EN,
1448e43ccb0aSPaul Kocialkowski 				 mode->binning_y ? OV5648_TC20_BINNING_VERT_EN :
1449e43ccb0aSPaul Kocialkowski 				 0);
1450e43ccb0aSPaul Kocialkowski 	if (ret)
1451e43ccb0aSPaul Kocialkowski 		return ret;
1452e43ccb0aSPaul Kocialkowski 
1453e43ccb0aSPaul Kocialkowski 	ret = ov5648_update_bits(sensor, OV5648_TC21_REG,
1454e43ccb0aSPaul Kocialkowski 				 OV5648_TC21_BINNING_HORZ_EN,
1455e43ccb0aSPaul Kocialkowski 				 mode->binning_x ? OV5648_TC21_BINNING_HORZ_EN :
1456e43ccb0aSPaul Kocialkowski 				 0);
1457e43ccb0aSPaul Kocialkowski 	if (ret)
1458e43ccb0aSPaul Kocialkowski 		return ret;
1459e43ccb0aSPaul Kocialkowski 
1460e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_SUB_INC_X_REG,
1461e43ccb0aSPaul Kocialkowski 			   OV5648_SUB_INC_X_ODD(mode->inc_x_odd) |
1462e43ccb0aSPaul Kocialkowski 			   OV5648_SUB_INC_X_EVEN(mode->inc_x_even));
1463e43ccb0aSPaul Kocialkowski 	if (ret)
1464e43ccb0aSPaul Kocialkowski 		return ret;
1465e43ccb0aSPaul Kocialkowski 
1466e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_SUB_INC_Y_REG,
1467e43ccb0aSPaul Kocialkowski 			   OV5648_SUB_INC_Y_ODD(mode->inc_y_odd) |
1468e43ccb0aSPaul Kocialkowski 			   OV5648_SUB_INC_Y_EVEN(mode->inc_y_even));
1469e43ccb0aSPaul Kocialkowski 	if (ret)
1470e43ccb0aSPaul Kocialkowski 		return ret;
1471e43ccb0aSPaul Kocialkowski 
1472e43ccb0aSPaul Kocialkowski 	/* PLLs */
1473e43ccb0aSPaul Kocialkowski 
1474e43ccb0aSPaul Kocialkowski 	ret = ov5648_mode_pll1_configure(sensor, mode, mbus_code);
1475e43ccb0aSPaul Kocialkowski 	if (ret)
1476e43ccb0aSPaul Kocialkowski 		return ret;
1477e43ccb0aSPaul Kocialkowski 
1478e43ccb0aSPaul Kocialkowski 	ret = ov5648_mode_pll2_configure(sensor, mode);
1479e43ccb0aSPaul Kocialkowski 	if (ret)
1480e43ccb0aSPaul Kocialkowski 		return ret;
1481e43ccb0aSPaul Kocialkowski 
1482e43ccb0aSPaul Kocialkowski 	/* Extra registers */
1483e43ccb0aSPaul Kocialkowski 
1484e43ccb0aSPaul Kocialkowski 	if (mode->register_values) {
1485e43ccb0aSPaul Kocialkowski 		ret = ov5648_write_sequence(sensor, mode->register_values,
1486e43ccb0aSPaul Kocialkowski 					    mode->register_values_count);
1487e43ccb0aSPaul Kocialkowski 		if (ret)
1488e43ccb0aSPaul Kocialkowski 			return ret;
1489e43ccb0aSPaul Kocialkowski 	}
1490e43ccb0aSPaul Kocialkowski 
1491e43ccb0aSPaul Kocialkowski 	return 0;
1492e43ccb0aSPaul Kocialkowski }
1493e43ccb0aSPaul Kocialkowski 
ov5648_mode_mipi_clk_rate(struct ov5648_sensor * sensor,const struct ov5648_mode * mode,u32 mbus_code)1494e43ccb0aSPaul Kocialkowski static unsigned long ov5648_mode_mipi_clk_rate(struct ov5648_sensor *sensor,
1495e43ccb0aSPaul Kocialkowski 					       const struct ov5648_mode *mode,
1496e43ccb0aSPaul Kocialkowski 					       u32 mbus_code)
1497e43ccb0aSPaul Kocialkowski {
1498e43ccb0aSPaul Kocialkowski 	const struct ov5648_pll1_config *config;
1499e43ccb0aSPaul Kocialkowski 	unsigned long pll1_rate;
1500e43ccb0aSPaul Kocialkowski 
1501e43ccb0aSPaul Kocialkowski 	switch (mbus_code) {
1502e43ccb0aSPaul Kocialkowski 	case MEDIA_BUS_FMT_SBGGR8_1X8:
1503e43ccb0aSPaul Kocialkowski 		config = mode->pll1_config[0];
1504e43ccb0aSPaul Kocialkowski 		break;
1505e43ccb0aSPaul Kocialkowski 	case MEDIA_BUS_FMT_SBGGR10_1X10:
1506e43ccb0aSPaul Kocialkowski 		config = mode->pll1_config[1];
1507e43ccb0aSPaul Kocialkowski 		break;
1508e43ccb0aSPaul Kocialkowski 	default:
1509e43ccb0aSPaul Kocialkowski 		return 0;
1510e43ccb0aSPaul Kocialkowski 	}
1511e43ccb0aSPaul Kocialkowski 
1512e43ccb0aSPaul Kocialkowski 	pll1_rate = ov5648_mode_pll1_rate(sensor, config);
1513e43ccb0aSPaul Kocialkowski 
1514e43ccb0aSPaul Kocialkowski 	return pll1_rate / config->sys_div / config->mipi_div / 2;
1515e43ccb0aSPaul Kocialkowski }
1516e43ccb0aSPaul Kocialkowski 
1517e43ccb0aSPaul Kocialkowski /* Exposure */
1518e43ccb0aSPaul Kocialkowski 
ov5648_exposure_auto_configure(struct ov5648_sensor * sensor,bool enable)1519e43ccb0aSPaul Kocialkowski static int ov5648_exposure_auto_configure(struct ov5648_sensor *sensor,
1520e43ccb0aSPaul Kocialkowski 					  bool enable)
1521e43ccb0aSPaul Kocialkowski {
1522e43ccb0aSPaul Kocialkowski 	return ov5648_update_bits(sensor, OV5648_MANUAL_CTRL_REG,
1523e43ccb0aSPaul Kocialkowski 				  OV5648_MANUAL_CTRL_AEC_MANUAL_EN,
1524e43ccb0aSPaul Kocialkowski 				  enable ? 0 : OV5648_MANUAL_CTRL_AEC_MANUAL_EN);
1525e43ccb0aSPaul Kocialkowski }
1526e43ccb0aSPaul Kocialkowski 
ov5648_exposure_configure(struct ov5648_sensor * sensor,u32 exposure)1527e43ccb0aSPaul Kocialkowski static int ov5648_exposure_configure(struct ov5648_sensor *sensor, u32 exposure)
1528e43ccb0aSPaul Kocialkowski {
1529e43ccb0aSPaul Kocialkowski 	struct ov5648_ctrls *ctrls = &sensor->ctrls;
1530e43ccb0aSPaul Kocialkowski 	int ret;
1531e43ccb0aSPaul Kocialkowski 
1532e43ccb0aSPaul Kocialkowski 	if (ctrls->exposure_auto->val != V4L2_EXPOSURE_MANUAL)
1533e43ccb0aSPaul Kocialkowski 		return -EINVAL;
1534e43ccb0aSPaul Kocialkowski 
1535e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_EXPOSURE_CTRL_HH_REG,
1536e43ccb0aSPaul Kocialkowski 			   OV5648_EXPOSURE_CTRL_HH(exposure));
1537e43ccb0aSPaul Kocialkowski 	if (ret)
1538e43ccb0aSPaul Kocialkowski 		return ret;
1539e43ccb0aSPaul Kocialkowski 
1540e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_EXPOSURE_CTRL_H_REG,
1541e43ccb0aSPaul Kocialkowski 			   OV5648_EXPOSURE_CTRL_H(exposure));
1542e43ccb0aSPaul Kocialkowski 	if (ret)
1543e43ccb0aSPaul Kocialkowski 		return ret;
1544e43ccb0aSPaul Kocialkowski 
1545e43ccb0aSPaul Kocialkowski 	return ov5648_write(sensor, OV5648_EXPOSURE_CTRL_L_REG,
1546e43ccb0aSPaul Kocialkowski 			    OV5648_EXPOSURE_CTRL_L(exposure));
1547e43ccb0aSPaul Kocialkowski }
1548e43ccb0aSPaul Kocialkowski 
ov5648_exposure_value(struct ov5648_sensor * sensor,u32 * exposure)1549e43ccb0aSPaul Kocialkowski static int ov5648_exposure_value(struct ov5648_sensor *sensor,
1550e43ccb0aSPaul Kocialkowski 				 u32 *exposure)
1551e43ccb0aSPaul Kocialkowski {
1552e43ccb0aSPaul Kocialkowski 	u8 exposure_hh = 0, exposure_h = 0, exposure_l = 0;
1553e43ccb0aSPaul Kocialkowski 	int ret;
1554e43ccb0aSPaul Kocialkowski 
1555e43ccb0aSPaul Kocialkowski 	ret = ov5648_read(sensor, OV5648_EXPOSURE_CTRL_HH_REG, &exposure_hh);
1556e43ccb0aSPaul Kocialkowski 	if (ret)
1557e43ccb0aSPaul Kocialkowski 		return ret;
1558e43ccb0aSPaul Kocialkowski 
1559e43ccb0aSPaul Kocialkowski 	ret = ov5648_read(sensor, OV5648_EXPOSURE_CTRL_H_REG, &exposure_h);
1560e43ccb0aSPaul Kocialkowski 	if (ret)
1561e43ccb0aSPaul Kocialkowski 		return ret;
1562e43ccb0aSPaul Kocialkowski 
1563e43ccb0aSPaul Kocialkowski 	ret = ov5648_read(sensor, OV5648_EXPOSURE_CTRL_L_REG, &exposure_l);
1564e43ccb0aSPaul Kocialkowski 	if (ret)
1565e43ccb0aSPaul Kocialkowski 		return ret;
1566e43ccb0aSPaul Kocialkowski 
1567e43ccb0aSPaul Kocialkowski 	*exposure = OV5648_EXPOSURE_CTRL_HH_VALUE((u32)exposure_hh) |
1568e43ccb0aSPaul Kocialkowski 		    OV5648_EXPOSURE_CTRL_H_VALUE((u32)exposure_h) |
1569e43ccb0aSPaul Kocialkowski 		    OV5648_EXPOSURE_CTRL_L_VALUE((u32)exposure_l);
1570e43ccb0aSPaul Kocialkowski 
1571e43ccb0aSPaul Kocialkowski 	return 0;
1572e43ccb0aSPaul Kocialkowski }
1573e43ccb0aSPaul Kocialkowski 
1574e43ccb0aSPaul Kocialkowski /* Gain */
1575e43ccb0aSPaul Kocialkowski 
ov5648_gain_auto_configure(struct ov5648_sensor * sensor,bool enable)1576e43ccb0aSPaul Kocialkowski static int ov5648_gain_auto_configure(struct ov5648_sensor *sensor, bool enable)
1577e43ccb0aSPaul Kocialkowski {
1578e43ccb0aSPaul Kocialkowski 	return ov5648_update_bits(sensor, OV5648_MANUAL_CTRL_REG,
1579e43ccb0aSPaul Kocialkowski 				  OV5648_MANUAL_CTRL_AGC_MANUAL_EN,
1580e43ccb0aSPaul Kocialkowski 				  enable ? 0 : OV5648_MANUAL_CTRL_AGC_MANUAL_EN);
1581e43ccb0aSPaul Kocialkowski }
1582e43ccb0aSPaul Kocialkowski 
ov5648_gain_configure(struct ov5648_sensor * sensor,u32 gain)1583e43ccb0aSPaul Kocialkowski static int ov5648_gain_configure(struct ov5648_sensor *sensor, u32 gain)
1584e43ccb0aSPaul Kocialkowski {
1585e43ccb0aSPaul Kocialkowski 	struct ov5648_ctrls *ctrls = &sensor->ctrls;
1586e43ccb0aSPaul Kocialkowski 	int ret;
1587e43ccb0aSPaul Kocialkowski 
1588e43ccb0aSPaul Kocialkowski 	if (ctrls->gain_auto->val)
1589e43ccb0aSPaul Kocialkowski 		return -EINVAL;
1590e43ccb0aSPaul Kocialkowski 
1591e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_GAIN_CTRL_H_REG,
1592e43ccb0aSPaul Kocialkowski 			   OV5648_GAIN_CTRL_H(gain));
1593e43ccb0aSPaul Kocialkowski 	if (ret)
1594e43ccb0aSPaul Kocialkowski 		return ret;
1595e43ccb0aSPaul Kocialkowski 
1596e43ccb0aSPaul Kocialkowski 	return ov5648_write(sensor, OV5648_GAIN_CTRL_L_REG,
1597e43ccb0aSPaul Kocialkowski 			    OV5648_GAIN_CTRL_L(gain));
1598e43ccb0aSPaul Kocialkowski }
1599e43ccb0aSPaul Kocialkowski 
ov5648_gain_value(struct ov5648_sensor * sensor,u32 * gain)1600e43ccb0aSPaul Kocialkowski static int ov5648_gain_value(struct ov5648_sensor *sensor, u32 *gain)
1601e43ccb0aSPaul Kocialkowski {
1602e43ccb0aSPaul Kocialkowski 	u8 gain_h = 0, gain_l = 0;
1603e43ccb0aSPaul Kocialkowski 	int ret;
1604e43ccb0aSPaul Kocialkowski 
1605e43ccb0aSPaul Kocialkowski 	ret = ov5648_read(sensor, OV5648_GAIN_CTRL_H_REG, &gain_h);
1606e43ccb0aSPaul Kocialkowski 	if (ret)
1607e43ccb0aSPaul Kocialkowski 		return ret;
1608e43ccb0aSPaul Kocialkowski 
1609e43ccb0aSPaul Kocialkowski 	ret = ov5648_read(sensor, OV5648_GAIN_CTRL_L_REG, &gain_l);
1610e43ccb0aSPaul Kocialkowski 	if (ret)
1611e43ccb0aSPaul Kocialkowski 		return ret;
1612e43ccb0aSPaul Kocialkowski 
1613e43ccb0aSPaul Kocialkowski 	*gain = OV5648_GAIN_CTRL_H_VALUE((u32)gain_h) |
1614e43ccb0aSPaul Kocialkowski 		OV5648_GAIN_CTRL_L_VALUE((u32)gain_l);
1615e43ccb0aSPaul Kocialkowski 
1616e43ccb0aSPaul Kocialkowski 	return 0;
1617e43ccb0aSPaul Kocialkowski }
1618e43ccb0aSPaul Kocialkowski 
1619e43ccb0aSPaul Kocialkowski /* White Balance */
1620e43ccb0aSPaul Kocialkowski 
ov5648_white_balance_auto_configure(struct ov5648_sensor * sensor,bool enable)1621e43ccb0aSPaul Kocialkowski static int ov5648_white_balance_auto_configure(struct ov5648_sensor *sensor,
1622e43ccb0aSPaul Kocialkowski 					       bool enable)
1623e43ccb0aSPaul Kocialkowski {
1624e43ccb0aSPaul Kocialkowski 	return ov5648_write(sensor, OV5648_AWB_CTRL_REG,
1625e43ccb0aSPaul Kocialkowski 			    enable ? 0 : OV5648_AWB_CTRL_GAIN_MANUAL_EN);
1626e43ccb0aSPaul Kocialkowski }
1627e43ccb0aSPaul Kocialkowski 
ov5648_white_balance_configure(struct ov5648_sensor * sensor,u32 red_balance,u32 blue_balance)1628e43ccb0aSPaul Kocialkowski static int ov5648_white_balance_configure(struct ov5648_sensor *sensor,
1629e43ccb0aSPaul Kocialkowski 					  u32 red_balance, u32 blue_balance)
1630e43ccb0aSPaul Kocialkowski {
1631e43ccb0aSPaul Kocialkowski 	struct ov5648_ctrls *ctrls = &sensor->ctrls;
1632e43ccb0aSPaul Kocialkowski 	int ret;
1633e43ccb0aSPaul Kocialkowski 
1634e43ccb0aSPaul Kocialkowski 	if (ctrls->white_balance_auto->val)
1635e43ccb0aSPaul Kocialkowski 		return -EINVAL;
1636e43ccb0aSPaul Kocialkowski 
1637e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_GAIN_RED_MAN_H_REG,
1638e43ccb0aSPaul Kocialkowski 			   OV5648_GAIN_RED_MAN_H(red_balance));
1639e43ccb0aSPaul Kocialkowski 	if (ret)
1640e43ccb0aSPaul Kocialkowski 		return ret;
1641e43ccb0aSPaul Kocialkowski 
1642e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_GAIN_RED_MAN_L_REG,
1643e43ccb0aSPaul Kocialkowski 			   OV5648_GAIN_RED_MAN_L(red_balance));
1644e43ccb0aSPaul Kocialkowski 	if (ret)
1645e43ccb0aSPaul Kocialkowski 		return ret;
1646e43ccb0aSPaul Kocialkowski 
1647e43ccb0aSPaul Kocialkowski 	ret = ov5648_write(sensor, OV5648_GAIN_BLUE_MAN_H_REG,
1648e43ccb0aSPaul Kocialkowski 			   OV5648_GAIN_BLUE_MAN_H(blue_balance));
1649e43ccb0aSPaul Kocialkowski 	if (ret)
1650e43ccb0aSPaul Kocialkowski 		return ret;
1651e43ccb0aSPaul Kocialkowski 
1652e43ccb0aSPaul Kocialkowski 	return ov5648_write(sensor, OV5648_GAIN_BLUE_MAN_L_REG,
1653e43ccb0aSPaul Kocialkowski 			    OV5648_GAIN_BLUE_MAN_L(blue_balance));
1654e43ccb0aSPaul Kocialkowski }
1655e43ccb0aSPaul Kocialkowski 
1656e43ccb0aSPaul Kocialkowski /* Flip */
1657e43ccb0aSPaul Kocialkowski 
ov5648_flip_vert_configure(struct ov5648_sensor * sensor,bool enable)1658e43ccb0aSPaul Kocialkowski static int ov5648_flip_vert_configure(struct ov5648_sensor *sensor, bool enable)
1659e43ccb0aSPaul Kocialkowski {
1660e43ccb0aSPaul Kocialkowski 	u8 bits = OV5648_TC20_FLIP_VERT_ISP_EN |
1661e43ccb0aSPaul Kocialkowski 		  OV5648_TC20_FLIP_VERT_SENSOR_EN;
1662e43ccb0aSPaul Kocialkowski 
1663e43ccb0aSPaul Kocialkowski 	return ov5648_update_bits(sensor, OV5648_TC20_REG, bits,
1664e43ccb0aSPaul Kocialkowski 				  enable ? bits : 0);
1665e43ccb0aSPaul Kocialkowski }
1666e43ccb0aSPaul Kocialkowski 
ov5648_flip_horz_configure(struct ov5648_sensor * sensor,bool enable)1667e43ccb0aSPaul Kocialkowski static int ov5648_flip_horz_configure(struct ov5648_sensor *sensor, bool enable)
1668e43ccb0aSPaul Kocialkowski {
1669e43ccb0aSPaul Kocialkowski 	u8 bits = OV5648_TC21_FLIP_HORZ_ISP_EN |
1670e43ccb0aSPaul Kocialkowski 		  OV5648_TC21_FLIP_HORZ_SENSOR_EN;
1671e43ccb0aSPaul Kocialkowski 
1672e43ccb0aSPaul Kocialkowski 	return ov5648_update_bits(sensor, OV5648_TC21_REG, bits,
1673e43ccb0aSPaul Kocialkowski 				  enable ? bits : 0);
1674e43ccb0aSPaul Kocialkowski }
1675e43ccb0aSPaul Kocialkowski 
1676e43ccb0aSPaul Kocialkowski /* Test Pattern */
1677e43ccb0aSPaul Kocialkowski 
ov5648_test_pattern_configure(struct ov5648_sensor * sensor,unsigned int index)1678e43ccb0aSPaul Kocialkowski static int ov5648_test_pattern_configure(struct ov5648_sensor *sensor,
1679e43ccb0aSPaul Kocialkowski 					 unsigned int index)
1680e43ccb0aSPaul Kocialkowski {
1681e43ccb0aSPaul Kocialkowski 	if (index >= ARRAY_SIZE(ov5648_test_pattern_bits))
1682e43ccb0aSPaul Kocialkowski 		return -EINVAL;
1683e43ccb0aSPaul Kocialkowski 
1684e43ccb0aSPaul Kocialkowski 	return ov5648_write(sensor, OV5648_ISP_CTRL3D_REG,
1685e43ccb0aSPaul Kocialkowski 			    ov5648_test_pattern_bits[index]);
1686e43ccb0aSPaul Kocialkowski }
1687e43ccb0aSPaul Kocialkowski 
1688e43ccb0aSPaul Kocialkowski /* State */
1689e43ccb0aSPaul Kocialkowski 
ov5648_state_mipi_configure(struct ov5648_sensor * sensor,const struct ov5648_mode * mode,u32 mbus_code)1690e43ccb0aSPaul Kocialkowski static int ov5648_state_mipi_configure(struct ov5648_sensor *sensor,
1691e43ccb0aSPaul Kocialkowski 				       const struct ov5648_mode *mode,
1692e43ccb0aSPaul Kocialkowski 				       u32 mbus_code)
1693e43ccb0aSPaul Kocialkowski {
1694e43ccb0aSPaul Kocialkowski 	struct ov5648_ctrls *ctrls = &sensor->ctrls;
169594d964e5SLaurent Pinchart 	struct v4l2_mbus_config_mipi_csi2 *bus_mipi_csi2 =
1696e43ccb0aSPaul Kocialkowski 		&sensor->endpoint.bus.mipi_csi2;
1697e43ccb0aSPaul Kocialkowski 	unsigned long mipi_clk_rate;
1698e43ccb0aSPaul Kocialkowski 	unsigned int bits_per_sample;
1699e43ccb0aSPaul Kocialkowski 	unsigned int lanes_count;
1700e43ccb0aSPaul Kocialkowski 	unsigned int i, j;
1701e43ccb0aSPaul Kocialkowski 	s64 mipi_pixel_rate;
1702e43ccb0aSPaul Kocialkowski 
1703e43ccb0aSPaul Kocialkowski 	mipi_clk_rate = ov5648_mode_mipi_clk_rate(sensor, mode, mbus_code);
1704e43ccb0aSPaul Kocialkowski 	if (!mipi_clk_rate)
1705e43ccb0aSPaul Kocialkowski 		return -EINVAL;
1706e43ccb0aSPaul Kocialkowski 
1707e43ccb0aSPaul Kocialkowski 	for (i = 0; i < ARRAY_SIZE(ov5648_link_freq_menu); i++) {
1708e43ccb0aSPaul Kocialkowski 		s64 freq = ov5648_link_freq_menu[i];
1709e43ccb0aSPaul Kocialkowski 
1710e43ccb0aSPaul Kocialkowski 		if (freq == mipi_clk_rate)
1711e43ccb0aSPaul Kocialkowski 			break;
1712e43ccb0aSPaul Kocialkowski 	}
1713e43ccb0aSPaul Kocialkowski 
1714e43ccb0aSPaul Kocialkowski 	for (j = 0; j < sensor->endpoint.nr_of_link_frequencies; j++) {
1715e43ccb0aSPaul Kocialkowski 		u64 freq = sensor->endpoint.link_frequencies[j];
1716e43ccb0aSPaul Kocialkowski 
1717e43ccb0aSPaul Kocialkowski 		if (freq == mipi_clk_rate)
1718e43ccb0aSPaul Kocialkowski 			break;
1719e43ccb0aSPaul Kocialkowski 	}
1720e43ccb0aSPaul Kocialkowski 
1721e43ccb0aSPaul Kocialkowski 	if (i == ARRAY_SIZE(ov5648_link_freq_menu)) {
1722e43ccb0aSPaul Kocialkowski 		dev_err(sensor->dev,
1723e43ccb0aSPaul Kocialkowski 			"failed to find %lu clk rate in link freq\n",
1724e43ccb0aSPaul Kocialkowski 			mipi_clk_rate);
1725e43ccb0aSPaul Kocialkowski 	} else if (j == sensor->endpoint.nr_of_link_frequencies) {
1726e43ccb0aSPaul Kocialkowski 		dev_err(sensor->dev,
1727e43ccb0aSPaul Kocialkowski 			"failed to find %lu clk rate in endpoint link-frequencies\n",
1728e43ccb0aSPaul Kocialkowski 			mipi_clk_rate);
1729e43ccb0aSPaul Kocialkowski 	} else {
1730e43ccb0aSPaul Kocialkowski 		__v4l2_ctrl_s_ctrl(ctrls->link_freq, i);
1731e43ccb0aSPaul Kocialkowski 	}
1732e43ccb0aSPaul Kocialkowski 
1733e43ccb0aSPaul Kocialkowski 	switch (mbus_code) {
1734e43ccb0aSPaul Kocialkowski 	case MEDIA_BUS_FMT_SBGGR8_1X8:
1735e43ccb0aSPaul Kocialkowski 		bits_per_sample = 8;
1736e43ccb0aSPaul Kocialkowski 		break;
1737e43ccb0aSPaul Kocialkowski 	case MEDIA_BUS_FMT_SBGGR10_1X10:
1738e43ccb0aSPaul Kocialkowski 		bits_per_sample = 10;
1739e43ccb0aSPaul Kocialkowski 		break;
1740e43ccb0aSPaul Kocialkowski 	default:
1741e43ccb0aSPaul Kocialkowski 		return -EINVAL;
1742e43ccb0aSPaul Kocialkowski 	}
1743e43ccb0aSPaul Kocialkowski 
1744e43ccb0aSPaul Kocialkowski 	lanes_count = bus_mipi_csi2->num_data_lanes;
1745e43ccb0aSPaul Kocialkowski 	mipi_pixel_rate = mipi_clk_rate * 2 * lanes_count / bits_per_sample;
1746e43ccb0aSPaul Kocialkowski 
1747e43ccb0aSPaul Kocialkowski 	__v4l2_ctrl_s_ctrl_int64(ctrls->pixel_rate, mipi_pixel_rate);
1748e43ccb0aSPaul Kocialkowski 
1749e43ccb0aSPaul Kocialkowski 	return 0;
1750e43ccb0aSPaul Kocialkowski }
1751e43ccb0aSPaul Kocialkowski 
ov5648_state_configure(struct ov5648_sensor * sensor,const struct ov5648_mode * mode,u32 mbus_code)1752e43ccb0aSPaul Kocialkowski static int ov5648_state_configure(struct ov5648_sensor *sensor,
1753e43ccb0aSPaul Kocialkowski 				  const struct ov5648_mode *mode,
1754e43ccb0aSPaul Kocialkowski 				  u32 mbus_code)
1755e43ccb0aSPaul Kocialkowski {
1756e43ccb0aSPaul Kocialkowski 	int ret;
1757e43ccb0aSPaul Kocialkowski 
1758e43ccb0aSPaul Kocialkowski 	if (sensor->state.streaming)
1759e43ccb0aSPaul Kocialkowski 		return -EBUSY;
1760e43ccb0aSPaul Kocialkowski 
1761e43ccb0aSPaul Kocialkowski 	/* State will be configured at first power on otherwise. */
1762e43ccb0aSPaul Kocialkowski 	if (pm_runtime_enabled(sensor->dev) &&
1763e43ccb0aSPaul Kocialkowski 	    !pm_runtime_suspended(sensor->dev)) {
1764e43ccb0aSPaul Kocialkowski 		ret = ov5648_mode_configure(sensor, mode, mbus_code);
1765e43ccb0aSPaul Kocialkowski 		if (ret)
1766e43ccb0aSPaul Kocialkowski 			return ret;
1767e43ccb0aSPaul Kocialkowski 	}
1768e43ccb0aSPaul Kocialkowski 
1769e43ccb0aSPaul Kocialkowski 	ret = ov5648_state_mipi_configure(sensor, mode, mbus_code);
1770e43ccb0aSPaul Kocialkowski 	if (ret)
1771e43ccb0aSPaul Kocialkowski 		return ret;
1772e43ccb0aSPaul Kocialkowski 
1773e43ccb0aSPaul Kocialkowski 	sensor->state.mode = mode;
1774e43ccb0aSPaul Kocialkowski 	sensor->state.mbus_code = mbus_code;
1775e43ccb0aSPaul Kocialkowski 
1776e43ccb0aSPaul Kocialkowski 	return 0;
1777e43ccb0aSPaul Kocialkowski }
1778e43ccb0aSPaul Kocialkowski 
ov5648_state_init(struct ov5648_sensor * sensor)1779e43ccb0aSPaul Kocialkowski static int ov5648_state_init(struct ov5648_sensor *sensor)
1780e43ccb0aSPaul Kocialkowski {
1781d4cb5d3cSHans de Goede 	int ret;
1782d4cb5d3cSHans de Goede 
1783d4cb5d3cSHans de Goede 	mutex_lock(&sensor->mutex);
1784d4cb5d3cSHans de Goede 	ret = ov5648_state_configure(sensor, &ov5648_modes[0],
1785e43ccb0aSPaul Kocialkowski 				     ov5648_mbus_codes[0]);
1786d4cb5d3cSHans de Goede 	mutex_unlock(&sensor->mutex);
1787d4cb5d3cSHans de Goede 
1788d4cb5d3cSHans de Goede 	return ret;
1789e43ccb0aSPaul Kocialkowski }
1790e43ccb0aSPaul Kocialkowski 
1791e43ccb0aSPaul Kocialkowski /* Sensor Base */
1792e43ccb0aSPaul Kocialkowski 
ov5648_sensor_init(struct ov5648_sensor * sensor)1793e43ccb0aSPaul Kocialkowski static int ov5648_sensor_init(struct ov5648_sensor *sensor)
1794e43ccb0aSPaul Kocialkowski {
1795e43ccb0aSPaul Kocialkowski 	int ret;
1796e43ccb0aSPaul Kocialkowski 
1797e43ccb0aSPaul Kocialkowski 	ret = ov5648_sw_reset(sensor);
1798e43ccb0aSPaul Kocialkowski 	if (ret) {
1799e43ccb0aSPaul Kocialkowski 		dev_err(sensor->dev, "failed to perform sw reset\n");
1800e43ccb0aSPaul Kocialkowski 		return ret;
1801e43ccb0aSPaul Kocialkowski 	}
1802e43ccb0aSPaul Kocialkowski 
1803e43ccb0aSPaul Kocialkowski 	ret = ov5648_sw_standby(sensor, 1);
1804e43ccb0aSPaul Kocialkowski 	if (ret) {
1805e43ccb0aSPaul Kocialkowski 		dev_err(sensor->dev, "failed to set sensor standby\n");
1806e43ccb0aSPaul Kocialkowski 		return ret;
1807e43ccb0aSPaul Kocialkowski 	}
1808e43ccb0aSPaul Kocialkowski 
1809e43ccb0aSPaul Kocialkowski 	ret = ov5648_chip_id_check(sensor);
1810e43ccb0aSPaul Kocialkowski 	if (ret) {
1811e43ccb0aSPaul Kocialkowski 		dev_err(sensor->dev, "failed to check sensor chip id\n");
1812e43ccb0aSPaul Kocialkowski 		return ret;
1813e43ccb0aSPaul Kocialkowski 	}
1814e43ccb0aSPaul Kocialkowski 
1815e43ccb0aSPaul Kocialkowski 	ret = ov5648_avdd_internal_power(sensor, !sensor->avdd);
1816e43ccb0aSPaul Kocialkowski 	if (ret) {
1817e43ccb0aSPaul Kocialkowski 		dev_err(sensor->dev, "failed to set internal avdd power\n");
1818e43ccb0aSPaul Kocialkowski 		return ret;
1819e43ccb0aSPaul Kocialkowski 	}
1820e43ccb0aSPaul Kocialkowski 
1821e43ccb0aSPaul Kocialkowski 	ret = ov5648_write_sequence(sensor, ov5648_init_sequence,
1822e43ccb0aSPaul Kocialkowski 				    ARRAY_SIZE(ov5648_init_sequence));
1823e43ccb0aSPaul Kocialkowski 	if (ret) {
1824e43ccb0aSPaul Kocialkowski 		dev_err(sensor->dev, "failed to write init sequence\n");
1825e43ccb0aSPaul Kocialkowski 		return ret;
1826e43ccb0aSPaul Kocialkowski 	}
1827e43ccb0aSPaul Kocialkowski 
1828e43ccb0aSPaul Kocialkowski 	ret = ov5648_pad_configure(sensor);
1829e43ccb0aSPaul Kocialkowski 	if (ret) {
1830e43ccb0aSPaul Kocialkowski 		dev_err(sensor->dev, "failed to configure pad\n");
1831e43ccb0aSPaul Kocialkowski 		return ret;
1832e43ccb0aSPaul Kocialkowski 	}
1833e43ccb0aSPaul Kocialkowski 
1834e43ccb0aSPaul Kocialkowski 	ret = ov5648_mipi_configure(sensor);
1835e43ccb0aSPaul Kocialkowski 	if (ret) {
1836e43ccb0aSPaul Kocialkowski 		dev_err(sensor->dev, "failed to configure MIPI\n");
1837e43ccb0aSPaul Kocialkowski 		return ret;
1838e43ccb0aSPaul Kocialkowski 	}
1839e43ccb0aSPaul Kocialkowski 
1840e43ccb0aSPaul Kocialkowski 	ret = ov5648_isp_configure(sensor);
1841e43ccb0aSPaul Kocialkowski 	if (ret) {
1842e43ccb0aSPaul Kocialkowski 		dev_err(sensor->dev, "failed to configure ISP\n");
1843e43ccb0aSPaul Kocialkowski 		return ret;
1844e43ccb0aSPaul Kocialkowski 	}
1845e43ccb0aSPaul Kocialkowski 
1846e43ccb0aSPaul Kocialkowski 	ret = ov5648_black_level_configure(sensor);
1847e43ccb0aSPaul Kocialkowski 	if (ret) {
1848e43ccb0aSPaul Kocialkowski 		dev_err(sensor->dev, "failed to configure black level\n");
1849e43ccb0aSPaul Kocialkowski 		return ret;
1850e43ccb0aSPaul Kocialkowski 	}
1851e43ccb0aSPaul Kocialkowski 
1852e43ccb0aSPaul Kocialkowski 	/* Configure current mode. */
1853e43ccb0aSPaul Kocialkowski 	ret = ov5648_state_configure(sensor, sensor->state.mode,
1854e43ccb0aSPaul Kocialkowski 				     sensor->state.mbus_code);
1855e43ccb0aSPaul Kocialkowski 	if (ret) {
1856e43ccb0aSPaul Kocialkowski 		dev_err(sensor->dev, "failed to configure state\n");
1857e43ccb0aSPaul Kocialkowski 		return ret;
1858e43ccb0aSPaul Kocialkowski 	}
1859e43ccb0aSPaul Kocialkowski 
1860e43ccb0aSPaul Kocialkowski 	return 0;
1861e43ccb0aSPaul Kocialkowski }
1862e43ccb0aSPaul Kocialkowski 
ov5648_sensor_power(struct ov5648_sensor * sensor,bool on)1863e43ccb0aSPaul Kocialkowski static int ov5648_sensor_power(struct ov5648_sensor *sensor, bool on)
1864e43ccb0aSPaul Kocialkowski {
1865e43ccb0aSPaul Kocialkowski 	/* Keep initialized to zero for disable label. */
1866e43ccb0aSPaul Kocialkowski 	int ret = 0;
1867e43ccb0aSPaul Kocialkowski 
1868e43ccb0aSPaul Kocialkowski 	/*
1869e43ccb0aSPaul Kocialkowski 	 * General notes about the power sequence:
1870e43ccb0aSPaul Kocialkowski 	 * - power-down GPIO must be active (low) during power-on;
1871e43ccb0aSPaul Kocialkowski 	 * - reset GPIO state does not matter during power-on;
1872e43ccb0aSPaul Kocialkowski 	 * - XVCLK must be provided 1 ms before register access;
1873e43ccb0aSPaul Kocialkowski 	 * - 10 ms are needed between power-down deassert and register access.
1874e43ccb0aSPaul Kocialkowski 	 */
1875e43ccb0aSPaul Kocialkowski 
1876e43ccb0aSPaul Kocialkowski 	/* Note that regulator-and-GPIO-based power is untested. */
1877e43ccb0aSPaul Kocialkowski 	if (on) {
1878e43ccb0aSPaul Kocialkowski 		gpiod_set_value_cansleep(sensor->reset, 1);
1879e43ccb0aSPaul Kocialkowski 		gpiod_set_value_cansleep(sensor->powerdown, 1);
1880e43ccb0aSPaul Kocialkowski 
1881e43ccb0aSPaul Kocialkowski 		ret = regulator_enable(sensor->dovdd);
1882e43ccb0aSPaul Kocialkowski 		if (ret) {
1883e43ccb0aSPaul Kocialkowski 			dev_err(sensor->dev,
1884e43ccb0aSPaul Kocialkowski 				"failed to enable DOVDD regulator\n");
1885e43ccb0aSPaul Kocialkowski 			goto disable;
1886e43ccb0aSPaul Kocialkowski 		}
1887e43ccb0aSPaul Kocialkowski 
1888e43ccb0aSPaul Kocialkowski 		if (sensor->avdd) {
1889e43ccb0aSPaul Kocialkowski 			ret = regulator_enable(sensor->avdd);
1890e43ccb0aSPaul Kocialkowski 			if (ret) {
1891e43ccb0aSPaul Kocialkowski 				dev_err(sensor->dev,
1892e43ccb0aSPaul Kocialkowski 					"failed to enable AVDD regulator\n");
1893e43ccb0aSPaul Kocialkowski 				goto disable;
1894e43ccb0aSPaul Kocialkowski 			}
1895e43ccb0aSPaul Kocialkowski 		}
1896e43ccb0aSPaul Kocialkowski 
1897e43ccb0aSPaul Kocialkowski 		ret = regulator_enable(sensor->dvdd);
1898e43ccb0aSPaul Kocialkowski 		if (ret) {
1899e43ccb0aSPaul Kocialkowski 			dev_err(sensor->dev,
1900e43ccb0aSPaul Kocialkowski 				"failed to enable DVDD regulator\n");
1901e43ccb0aSPaul Kocialkowski 			goto disable;
1902e43ccb0aSPaul Kocialkowski 		}
1903e43ccb0aSPaul Kocialkowski 
1904e43ccb0aSPaul Kocialkowski 		/* According to OV5648 power up diagram. */
1905e43ccb0aSPaul Kocialkowski 		usleep_range(5000, 10000);
1906e43ccb0aSPaul Kocialkowski 
1907e43ccb0aSPaul Kocialkowski 		ret = clk_prepare_enable(sensor->xvclk);
1908e43ccb0aSPaul Kocialkowski 		if (ret) {
1909e43ccb0aSPaul Kocialkowski 			dev_err(sensor->dev, "failed to enable XVCLK clock\n");
1910e43ccb0aSPaul Kocialkowski 			goto disable;
1911e43ccb0aSPaul Kocialkowski 		}
1912e43ccb0aSPaul Kocialkowski 
1913e43ccb0aSPaul Kocialkowski 		gpiod_set_value_cansleep(sensor->reset, 0);
1914e43ccb0aSPaul Kocialkowski 		gpiod_set_value_cansleep(sensor->powerdown, 0);
1915e43ccb0aSPaul Kocialkowski 
1916e43ccb0aSPaul Kocialkowski 		usleep_range(20000, 25000);
1917e43ccb0aSPaul Kocialkowski 	} else {
1918e43ccb0aSPaul Kocialkowski disable:
1919e43ccb0aSPaul Kocialkowski 		gpiod_set_value_cansleep(sensor->powerdown, 1);
1920e43ccb0aSPaul Kocialkowski 		gpiod_set_value_cansleep(sensor->reset, 1);
1921e43ccb0aSPaul Kocialkowski 
1922e43ccb0aSPaul Kocialkowski 		clk_disable_unprepare(sensor->xvclk);
1923e43ccb0aSPaul Kocialkowski 
1924e43ccb0aSPaul Kocialkowski 		regulator_disable(sensor->dvdd);
1925e43ccb0aSPaul Kocialkowski 
1926e43ccb0aSPaul Kocialkowski 		if (sensor->avdd)
1927e43ccb0aSPaul Kocialkowski 			regulator_disable(sensor->avdd);
1928e43ccb0aSPaul Kocialkowski 
1929e43ccb0aSPaul Kocialkowski 		regulator_disable(sensor->dovdd);
1930e43ccb0aSPaul Kocialkowski 	}
1931e43ccb0aSPaul Kocialkowski 
1932e43ccb0aSPaul Kocialkowski 	return ret;
1933e43ccb0aSPaul Kocialkowski }
1934e43ccb0aSPaul Kocialkowski 
1935e43ccb0aSPaul Kocialkowski /* Controls */
1936e43ccb0aSPaul Kocialkowski 
ov5648_g_volatile_ctrl(struct v4l2_ctrl * ctrl)1937e43ccb0aSPaul Kocialkowski static int ov5648_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
1938e43ccb0aSPaul Kocialkowski {
1939e43ccb0aSPaul Kocialkowski 	struct v4l2_subdev *subdev = ov5648_ctrl_subdev(ctrl);
1940e43ccb0aSPaul Kocialkowski 	struct ov5648_sensor *sensor = ov5648_subdev_sensor(subdev);
1941e43ccb0aSPaul Kocialkowski 	struct ov5648_ctrls *ctrls = &sensor->ctrls;
1942e43ccb0aSPaul Kocialkowski 	int ret;
1943e43ccb0aSPaul Kocialkowski 
1944e43ccb0aSPaul Kocialkowski 	switch (ctrl->id) {
1945e43ccb0aSPaul Kocialkowski 	case V4L2_CID_EXPOSURE_AUTO:
1946e43ccb0aSPaul Kocialkowski 		ret = ov5648_exposure_value(sensor, &ctrls->exposure->val);
1947e43ccb0aSPaul Kocialkowski 		if (ret)
1948e43ccb0aSPaul Kocialkowski 			return ret;
1949e43ccb0aSPaul Kocialkowski 		break;
1950e43ccb0aSPaul Kocialkowski 	case V4L2_CID_AUTOGAIN:
1951e43ccb0aSPaul Kocialkowski 		ret = ov5648_gain_value(sensor, &ctrls->gain->val);
1952e43ccb0aSPaul Kocialkowski 		if (ret)
1953e43ccb0aSPaul Kocialkowski 			return ret;
1954e43ccb0aSPaul Kocialkowski 		break;
1955e43ccb0aSPaul Kocialkowski 	default:
1956e43ccb0aSPaul Kocialkowski 		return -EINVAL;
1957e43ccb0aSPaul Kocialkowski 	}
1958e43ccb0aSPaul Kocialkowski 
1959e43ccb0aSPaul Kocialkowski 	return 0;
1960e43ccb0aSPaul Kocialkowski }
1961e43ccb0aSPaul Kocialkowski 
ov5648_s_ctrl(struct v4l2_ctrl * ctrl)1962e43ccb0aSPaul Kocialkowski static int ov5648_s_ctrl(struct v4l2_ctrl *ctrl)
1963e43ccb0aSPaul Kocialkowski {
1964e43ccb0aSPaul Kocialkowski 	struct v4l2_subdev *subdev = ov5648_ctrl_subdev(ctrl);
1965e43ccb0aSPaul Kocialkowski 	struct ov5648_sensor *sensor = ov5648_subdev_sensor(subdev);
1966e43ccb0aSPaul Kocialkowski 	struct ov5648_ctrls *ctrls = &sensor->ctrls;
1967e43ccb0aSPaul Kocialkowski 	unsigned int index;
1968e43ccb0aSPaul Kocialkowski 	bool enable;
1969e43ccb0aSPaul Kocialkowski 	int ret;
1970e43ccb0aSPaul Kocialkowski 
1971e43ccb0aSPaul Kocialkowski 	/* Wait for the sensor to be on before setting controls. */
1972e43ccb0aSPaul Kocialkowski 	if (pm_runtime_suspended(sensor->dev))
1973e43ccb0aSPaul Kocialkowski 		return 0;
1974e43ccb0aSPaul Kocialkowski 
1975e43ccb0aSPaul Kocialkowski 	switch (ctrl->id) {
1976e43ccb0aSPaul Kocialkowski 	case V4L2_CID_EXPOSURE_AUTO:
1977e43ccb0aSPaul Kocialkowski 		enable = ctrl->val == V4L2_EXPOSURE_AUTO;
1978e43ccb0aSPaul Kocialkowski 
1979e43ccb0aSPaul Kocialkowski 		ret = ov5648_exposure_auto_configure(sensor, enable);
1980e43ccb0aSPaul Kocialkowski 		if (ret)
1981e43ccb0aSPaul Kocialkowski 			return ret;
1982e43ccb0aSPaul Kocialkowski 
1983e43ccb0aSPaul Kocialkowski 		if (!enable && ctrls->exposure->is_new) {
1984e43ccb0aSPaul Kocialkowski 			ret = ov5648_exposure_configure(sensor,
1985e43ccb0aSPaul Kocialkowski 							ctrls->exposure->val);
1986e43ccb0aSPaul Kocialkowski 			if (ret)
1987e43ccb0aSPaul Kocialkowski 				return ret;
1988e43ccb0aSPaul Kocialkowski 		}
1989e43ccb0aSPaul Kocialkowski 		break;
1990e43ccb0aSPaul Kocialkowski 	case V4L2_CID_AUTOGAIN:
1991e43ccb0aSPaul Kocialkowski 		enable = !!ctrl->val;
1992e43ccb0aSPaul Kocialkowski 
1993e43ccb0aSPaul Kocialkowski 		ret = ov5648_gain_auto_configure(sensor, enable);
1994e43ccb0aSPaul Kocialkowski 		if (ret)
1995e43ccb0aSPaul Kocialkowski 			return ret;
1996e43ccb0aSPaul Kocialkowski 
1997e43ccb0aSPaul Kocialkowski 		if (!enable) {
1998e43ccb0aSPaul Kocialkowski 			ret = ov5648_gain_configure(sensor, ctrls->gain->val);
1999e43ccb0aSPaul Kocialkowski 			if (ret)
2000e43ccb0aSPaul Kocialkowski 				return ret;
2001e43ccb0aSPaul Kocialkowski 		}
2002e43ccb0aSPaul Kocialkowski 		break;
2003e43ccb0aSPaul Kocialkowski 	case V4L2_CID_AUTO_WHITE_BALANCE:
2004e43ccb0aSPaul Kocialkowski 		enable = !!ctrl->val;
2005e43ccb0aSPaul Kocialkowski 
2006e43ccb0aSPaul Kocialkowski 		ret = ov5648_white_balance_auto_configure(sensor, enable);
2007e43ccb0aSPaul Kocialkowski 		if (ret)
2008e43ccb0aSPaul Kocialkowski 			return ret;
2009e43ccb0aSPaul Kocialkowski 
2010e43ccb0aSPaul Kocialkowski 		if (!enable) {
2011e43ccb0aSPaul Kocialkowski 			ret = ov5648_white_balance_configure(sensor,
2012e43ccb0aSPaul Kocialkowski 							     ctrls->red_balance->val,
2013e43ccb0aSPaul Kocialkowski 							     ctrls->blue_balance->val);
2014e43ccb0aSPaul Kocialkowski 			if (ret)
2015e43ccb0aSPaul Kocialkowski 				return ret;
2016e43ccb0aSPaul Kocialkowski 		}
2017e43ccb0aSPaul Kocialkowski 		break;
2018e43ccb0aSPaul Kocialkowski 	case V4L2_CID_HFLIP:
2019e43ccb0aSPaul Kocialkowski 		enable = !!ctrl->val;
2020e43ccb0aSPaul Kocialkowski 		return ov5648_flip_horz_configure(sensor, enable);
2021e43ccb0aSPaul Kocialkowski 	case V4L2_CID_VFLIP:
2022e43ccb0aSPaul Kocialkowski 		enable = !!ctrl->val;
2023e43ccb0aSPaul Kocialkowski 		return ov5648_flip_vert_configure(sensor, enable);
2024e43ccb0aSPaul Kocialkowski 	case V4L2_CID_TEST_PATTERN:
2025e43ccb0aSPaul Kocialkowski 		index = (unsigned int)ctrl->val;
2026e43ccb0aSPaul Kocialkowski 		return ov5648_test_pattern_configure(sensor, index);
2027e43ccb0aSPaul Kocialkowski 	default:
2028e43ccb0aSPaul Kocialkowski 		return -EINVAL;
2029e43ccb0aSPaul Kocialkowski 	}
2030e43ccb0aSPaul Kocialkowski 
2031e43ccb0aSPaul Kocialkowski 	return 0;
2032e43ccb0aSPaul Kocialkowski }
2033e43ccb0aSPaul Kocialkowski 
2034e43ccb0aSPaul Kocialkowski static const struct v4l2_ctrl_ops ov5648_ctrl_ops = {
2035e43ccb0aSPaul Kocialkowski 	.g_volatile_ctrl	= ov5648_g_volatile_ctrl,
2036e43ccb0aSPaul Kocialkowski 	.s_ctrl			= ov5648_s_ctrl,
2037e43ccb0aSPaul Kocialkowski };
2038e43ccb0aSPaul Kocialkowski 
ov5648_ctrls_init(struct ov5648_sensor * sensor)2039e43ccb0aSPaul Kocialkowski static int ov5648_ctrls_init(struct ov5648_sensor *sensor)
2040e43ccb0aSPaul Kocialkowski {
2041e43ccb0aSPaul Kocialkowski 	struct ov5648_ctrls *ctrls = &sensor->ctrls;
2042e43ccb0aSPaul Kocialkowski 	struct v4l2_ctrl_handler *handler = &ctrls->handler;
2043e43ccb0aSPaul Kocialkowski 	const struct v4l2_ctrl_ops *ops = &ov5648_ctrl_ops;
2044e43ccb0aSPaul Kocialkowski 	int ret;
2045e43ccb0aSPaul Kocialkowski 
2046e43ccb0aSPaul Kocialkowski 	v4l2_ctrl_handler_init(handler, 32);
2047e43ccb0aSPaul Kocialkowski 
2048e43ccb0aSPaul Kocialkowski 	/* Use our mutex for ctrl locking. */
2049e43ccb0aSPaul Kocialkowski 	handler->lock = &sensor->mutex;
2050e43ccb0aSPaul Kocialkowski 
2051e43ccb0aSPaul Kocialkowski 	/* Exposure */
2052e43ccb0aSPaul Kocialkowski 
2053e43ccb0aSPaul Kocialkowski 	ctrls->exposure_auto = v4l2_ctrl_new_std_menu(handler, ops,
2054e43ccb0aSPaul Kocialkowski 						      V4L2_CID_EXPOSURE_AUTO,
2055e43ccb0aSPaul Kocialkowski 						      V4L2_EXPOSURE_MANUAL, 0,
2056e43ccb0aSPaul Kocialkowski 						      V4L2_EXPOSURE_AUTO);
2057e43ccb0aSPaul Kocialkowski 
2058e43ccb0aSPaul Kocialkowski 	ctrls->exposure = v4l2_ctrl_new_std(handler, ops, V4L2_CID_EXPOSURE,
2059e43ccb0aSPaul Kocialkowski 					    16, 1048575, 16, 512);
2060e43ccb0aSPaul Kocialkowski 
2061e43ccb0aSPaul Kocialkowski 	v4l2_ctrl_auto_cluster(2, &ctrls->exposure_auto, 1, true);
2062e43ccb0aSPaul Kocialkowski 
2063e43ccb0aSPaul Kocialkowski 	/* Gain */
2064e43ccb0aSPaul Kocialkowski 
2065e43ccb0aSPaul Kocialkowski 	ctrls->gain_auto =
2066e43ccb0aSPaul Kocialkowski 		v4l2_ctrl_new_std(handler, ops, V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
2067e43ccb0aSPaul Kocialkowski 
2068e43ccb0aSPaul Kocialkowski 	ctrls->gain = v4l2_ctrl_new_std(handler, ops, V4L2_CID_GAIN, 16, 1023,
2069e43ccb0aSPaul Kocialkowski 					16, 16);
2070e43ccb0aSPaul Kocialkowski 
2071e43ccb0aSPaul Kocialkowski 	v4l2_ctrl_auto_cluster(2, &ctrls->gain_auto, 0, true);
2072e43ccb0aSPaul Kocialkowski 
2073e43ccb0aSPaul Kocialkowski 	/* White Balance */
2074e43ccb0aSPaul Kocialkowski 
2075e43ccb0aSPaul Kocialkowski 	ctrls->white_balance_auto =
2076e43ccb0aSPaul Kocialkowski 		v4l2_ctrl_new_std(handler, ops, V4L2_CID_AUTO_WHITE_BALANCE, 0,
2077e43ccb0aSPaul Kocialkowski 				  1, 1, 1);
2078e43ccb0aSPaul Kocialkowski 
2079e43ccb0aSPaul Kocialkowski 	ctrls->red_balance = v4l2_ctrl_new_std(handler, ops,
2080e43ccb0aSPaul Kocialkowski 					       V4L2_CID_RED_BALANCE, 0, 4095,
2081e43ccb0aSPaul Kocialkowski 					       1, 1024);
2082e43ccb0aSPaul Kocialkowski 
2083e43ccb0aSPaul Kocialkowski 	ctrls->blue_balance = v4l2_ctrl_new_std(handler, ops,
2084e43ccb0aSPaul Kocialkowski 						V4L2_CID_BLUE_BALANCE, 0, 4095,
2085e43ccb0aSPaul Kocialkowski 						1, 1024);
2086e43ccb0aSPaul Kocialkowski 
2087e43ccb0aSPaul Kocialkowski 	v4l2_ctrl_auto_cluster(3, &ctrls->white_balance_auto, 0, false);
2088e43ccb0aSPaul Kocialkowski 
2089e43ccb0aSPaul Kocialkowski 	/* Flip */
2090e43ccb0aSPaul Kocialkowski 
2091e43ccb0aSPaul Kocialkowski 	v4l2_ctrl_new_std(handler, ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
2092e43ccb0aSPaul Kocialkowski 	v4l2_ctrl_new_std(handler, ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
2093e43ccb0aSPaul Kocialkowski 
2094e43ccb0aSPaul Kocialkowski 	/* Test Pattern */
2095e43ccb0aSPaul Kocialkowski 
2096e43ccb0aSPaul Kocialkowski 	v4l2_ctrl_new_std_menu_items(handler, ops, V4L2_CID_TEST_PATTERN,
2097e43ccb0aSPaul Kocialkowski 				     ARRAY_SIZE(ov5648_test_pattern_menu) - 1,
2098e43ccb0aSPaul Kocialkowski 				     0, 0, ov5648_test_pattern_menu);
2099e43ccb0aSPaul Kocialkowski 
2100e43ccb0aSPaul Kocialkowski 	/* MIPI CSI-2 */
2101e43ccb0aSPaul Kocialkowski 
2102e43ccb0aSPaul Kocialkowski 	ctrls->link_freq =
2103e43ccb0aSPaul Kocialkowski 		v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ,
2104e43ccb0aSPaul Kocialkowski 				       ARRAY_SIZE(ov5648_link_freq_menu) - 1,
2105e43ccb0aSPaul Kocialkowski 				       0, ov5648_link_freq_menu);
2106e43ccb0aSPaul Kocialkowski 
2107e43ccb0aSPaul Kocialkowski 	ctrls->pixel_rate =
2108e43ccb0aSPaul Kocialkowski 		v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE, 1,
2109e43ccb0aSPaul Kocialkowski 				  INT_MAX, 1, 1);
2110e43ccb0aSPaul Kocialkowski 
2111e43ccb0aSPaul Kocialkowski 	if (handler->error) {
2112e43ccb0aSPaul Kocialkowski 		ret = handler->error;
2113e43ccb0aSPaul Kocialkowski 		goto error_ctrls;
2114e43ccb0aSPaul Kocialkowski 	}
2115e43ccb0aSPaul Kocialkowski 
2116e43ccb0aSPaul Kocialkowski 	ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE;
2117e43ccb0aSPaul Kocialkowski 	ctrls->gain->flags |= V4L2_CTRL_FLAG_VOLATILE;
2118e43ccb0aSPaul Kocialkowski 
2119e43ccb0aSPaul Kocialkowski 	ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
2120e43ccb0aSPaul Kocialkowski 	ctrls->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY;
2121e43ccb0aSPaul Kocialkowski 
2122e43ccb0aSPaul Kocialkowski 	sensor->subdev.ctrl_handler = handler;
2123e43ccb0aSPaul Kocialkowski 
2124e43ccb0aSPaul Kocialkowski 	return 0;
2125e43ccb0aSPaul Kocialkowski 
2126e43ccb0aSPaul Kocialkowski error_ctrls:
2127e43ccb0aSPaul Kocialkowski 	v4l2_ctrl_handler_free(handler);
2128e43ccb0aSPaul Kocialkowski 
2129e43ccb0aSPaul Kocialkowski 	return ret;
2130e43ccb0aSPaul Kocialkowski }
2131e43ccb0aSPaul Kocialkowski 
2132e43ccb0aSPaul Kocialkowski /* Subdev Video Operations */
2133e43ccb0aSPaul Kocialkowski 
ov5648_s_stream(struct v4l2_subdev * subdev,int enable)2134e43ccb0aSPaul Kocialkowski static int ov5648_s_stream(struct v4l2_subdev *subdev, int enable)
2135e43ccb0aSPaul Kocialkowski {
2136e43ccb0aSPaul Kocialkowski 	struct ov5648_sensor *sensor = ov5648_subdev_sensor(subdev);
2137e43ccb0aSPaul Kocialkowski 	struct ov5648_state *state = &sensor->state;
2138e43ccb0aSPaul Kocialkowski 	int ret;
2139e43ccb0aSPaul Kocialkowski 
2140e43ccb0aSPaul Kocialkowski 	if (enable) {
21416b19d297SMauro Carvalho Chehab 		ret = pm_runtime_resume_and_get(sensor->dev);
21426b19d297SMauro Carvalho Chehab 		if (ret < 0)
2143e43ccb0aSPaul Kocialkowski 			return ret;
2144e43ccb0aSPaul Kocialkowski 	}
2145e43ccb0aSPaul Kocialkowski 
2146e43ccb0aSPaul Kocialkowski 	mutex_lock(&sensor->mutex);
2147e43ccb0aSPaul Kocialkowski 	ret = ov5648_sw_standby(sensor, !enable);
2148e43ccb0aSPaul Kocialkowski 	mutex_unlock(&sensor->mutex);
2149e43ccb0aSPaul Kocialkowski 
2150e43ccb0aSPaul Kocialkowski 	if (ret)
2151e43ccb0aSPaul Kocialkowski 		return ret;
2152e43ccb0aSPaul Kocialkowski 
2153e43ccb0aSPaul Kocialkowski 	state->streaming = !!enable;
2154e43ccb0aSPaul Kocialkowski 
2155e43ccb0aSPaul Kocialkowski 	if (!enable)
2156e43ccb0aSPaul Kocialkowski 		pm_runtime_put(sensor->dev);
2157e43ccb0aSPaul Kocialkowski 
2158e43ccb0aSPaul Kocialkowski 	return 0;
2159e43ccb0aSPaul Kocialkowski }
2160e43ccb0aSPaul Kocialkowski 
ov5648_g_frame_interval(struct v4l2_subdev * subdev,struct v4l2_subdev_frame_interval * interval)2161e43ccb0aSPaul Kocialkowski static int ov5648_g_frame_interval(struct v4l2_subdev *subdev,
2162e43ccb0aSPaul Kocialkowski 				   struct v4l2_subdev_frame_interval *interval)
2163e43ccb0aSPaul Kocialkowski {
2164e43ccb0aSPaul Kocialkowski 	struct ov5648_sensor *sensor = ov5648_subdev_sensor(subdev);
2165e43ccb0aSPaul Kocialkowski 	const struct ov5648_mode *mode;
2166e43ccb0aSPaul Kocialkowski 	int ret = 0;
2167e43ccb0aSPaul Kocialkowski 
2168e43ccb0aSPaul Kocialkowski 	mutex_lock(&sensor->mutex);
2169e43ccb0aSPaul Kocialkowski 
2170e43ccb0aSPaul Kocialkowski 	mode = sensor->state.mode;
2171e43ccb0aSPaul Kocialkowski 
2172e43ccb0aSPaul Kocialkowski 	switch (sensor->state.mbus_code) {
2173e43ccb0aSPaul Kocialkowski 	case MEDIA_BUS_FMT_SBGGR8_1X8:
2174e43ccb0aSPaul Kocialkowski 		interval->interval = mode->frame_interval[0];
2175e43ccb0aSPaul Kocialkowski 		break;
2176e43ccb0aSPaul Kocialkowski 	case MEDIA_BUS_FMT_SBGGR10_1X10:
2177e43ccb0aSPaul Kocialkowski 		interval->interval = mode->frame_interval[1];
2178e43ccb0aSPaul Kocialkowski 		break;
2179e43ccb0aSPaul Kocialkowski 	default:
2180e43ccb0aSPaul Kocialkowski 		ret = -EINVAL;
2181e43ccb0aSPaul Kocialkowski 	}
2182e43ccb0aSPaul Kocialkowski 
2183e43ccb0aSPaul Kocialkowski 	mutex_unlock(&sensor->mutex);
2184e43ccb0aSPaul Kocialkowski 
2185e43ccb0aSPaul Kocialkowski 	return ret;
2186e43ccb0aSPaul Kocialkowski }
2187e43ccb0aSPaul Kocialkowski 
2188e43ccb0aSPaul Kocialkowski static const struct v4l2_subdev_video_ops ov5648_subdev_video_ops = {
2189e43ccb0aSPaul Kocialkowski 	.s_stream		= ov5648_s_stream,
2190e43ccb0aSPaul Kocialkowski 	.g_frame_interval	= ov5648_g_frame_interval,
2191e43ccb0aSPaul Kocialkowski 	.s_frame_interval	= ov5648_g_frame_interval,
2192e43ccb0aSPaul Kocialkowski };
2193e43ccb0aSPaul Kocialkowski 
2194e43ccb0aSPaul Kocialkowski /* Subdev Pad Operations */
2195e43ccb0aSPaul Kocialkowski 
ov5648_enum_mbus_code(struct v4l2_subdev * subdev,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_mbus_code_enum * code_enum)2196e43ccb0aSPaul Kocialkowski static int ov5648_enum_mbus_code(struct v4l2_subdev *subdev,
21970d346d2aSTomi Valkeinen 				 struct v4l2_subdev_state *sd_state,
2198e43ccb0aSPaul Kocialkowski 				 struct v4l2_subdev_mbus_code_enum *code_enum)
2199e43ccb0aSPaul Kocialkowski {
2200e43ccb0aSPaul Kocialkowski 	if (code_enum->index >= ARRAY_SIZE(ov5648_mbus_codes))
2201e43ccb0aSPaul Kocialkowski 		return -EINVAL;
2202e43ccb0aSPaul Kocialkowski 
2203e43ccb0aSPaul Kocialkowski 	code_enum->code = ov5648_mbus_codes[code_enum->index];
2204e43ccb0aSPaul Kocialkowski 
2205e43ccb0aSPaul Kocialkowski 	return 0;
2206e43ccb0aSPaul Kocialkowski }
2207e43ccb0aSPaul Kocialkowski 
ov5648_mbus_format_fill(struct v4l2_mbus_framefmt * mbus_format,u32 mbus_code,const struct ov5648_mode * mode)2208e43ccb0aSPaul Kocialkowski static void ov5648_mbus_format_fill(struct v4l2_mbus_framefmt *mbus_format,
2209e43ccb0aSPaul Kocialkowski 				    u32 mbus_code,
2210e43ccb0aSPaul Kocialkowski 				    const struct ov5648_mode *mode)
2211e43ccb0aSPaul Kocialkowski {
2212e43ccb0aSPaul Kocialkowski 	mbus_format->width = mode->output_size_x;
2213e43ccb0aSPaul Kocialkowski 	mbus_format->height = mode->output_size_y;
2214e43ccb0aSPaul Kocialkowski 	mbus_format->code = mbus_code;
2215e43ccb0aSPaul Kocialkowski 
2216e43ccb0aSPaul Kocialkowski 	mbus_format->field = V4L2_FIELD_NONE;
2217e43ccb0aSPaul Kocialkowski 	mbus_format->colorspace = V4L2_COLORSPACE_RAW;
2218e43ccb0aSPaul Kocialkowski 	mbus_format->ycbcr_enc =
2219e43ccb0aSPaul Kocialkowski 		V4L2_MAP_YCBCR_ENC_DEFAULT(mbus_format->colorspace);
2220e43ccb0aSPaul Kocialkowski 	mbus_format->quantization = V4L2_QUANTIZATION_FULL_RANGE;
2221e43ccb0aSPaul Kocialkowski 	mbus_format->xfer_func =
2222e43ccb0aSPaul Kocialkowski 		V4L2_MAP_XFER_FUNC_DEFAULT(mbus_format->colorspace);
2223e43ccb0aSPaul Kocialkowski }
2224e43ccb0aSPaul Kocialkowski 
ov5648_get_fmt(struct v4l2_subdev * subdev,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * format)2225e43ccb0aSPaul Kocialkowski static int ov5648_get_fmt(struct v4l2_subdev *subdev,
22260d346d2aSTomi Valkeinen 			  struct v4l2_subdev_state *sd_state,
2227e43ccb0aSPaul Kocialkowski 			  struct v4l2_subdev_format *format)
2228e43ccb0aSPaul Kocialkowski {
2229e43ccb0aSPaul Kocialkowski 	struct ov5648_sensor *sensor = ov5648_subdev_sensor(subdev);
2230e43ccb0aSPaul Kocialkowski 	struct v4l2_mbus_framefmt *mbus_format = &format->format;
2231e43ccb0aSPaul Kocialkowski 
2232e43ccb0aSPaul Kocialkowski 	mutex_lock(&sensor->mutex);
2233e43ccb0aSPaul Kocialkowski 
2234e43ccb0aSPaul Kocialkowski 	if (format->which == V4L2_SUBDEV_FORMAT_TRY)
22350d346d2aSTomi Valkeinen 		*mbus_format = *v4l2_subdev_get_try_format(subdev, sd_state,
2236e43ccb0aSPaul Kocialkowski 							   format->pad);
2237e43ccb0aSPaul Kocialkowski 	else
2238e43ccb0aSPaul Kocialkowski 		ov5648_mbus_format_fill(mbus_format, sensor->state.mbus_code,
2239e43ccb0aSPaul Kocialkowski 					sensor->state.mode);
2240e43ccb0aSPaul Kocialkowski 
2241e43ccb0aSPaul Kocialkowski 	mutex_unlock(&sensor->mutex);
2242e43ccb0aSPaul Kocialkowski 
2243e43ccb0aSPaul Kocialkowski 	return 0;
2244e43ccb0aSPaul Kocialkowski }
2245e43ccb0aSPaul Kocialkowski 
ov5648_set_fmt(struct v4l2_subdev * subdev,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * format)2246e43ccb0aSPaul Kocialkowski static int ov5648_set_fmt(struct v4l2_subdev *subdev,
22470d346d2aSTomi Valkeinen 			  struct v4l2_subdev_state *sd_state,
2248e43ccb0aSPaul Kocialkowski 			  struct v4l2_subdev_format *format)
2249e43ccb0aSPaul Kocialkowski {
2250e43ccb0aSPaul Kocialkowski 	struct ov5648_sensor *sensor = ov5648_subdev_sensor(subdev);
2251e43ccb0aSPaul Kocialkowski 	struct v4l2_mbus_framefmt *mbus_format = &format->format;
2252e43ccb0aSPaul Kocialkowski 	const struct ov5648_mode *mode;
2253e43ccb0aSPaul Kocialkowski 	u32 mbus_code = 0;
2254e43ccb0aSPaul Kocialkowski 	unsigned int index;
2255e43ccb0aSPaul Kocialkowski 	int ret = 0;
2256e43ccb0aSPaul Kocialkowski 
2257e43ccb0aSPaul Kocialkowski 	mutex_lock(&sensor->mutex);
2258e43ccb0aSPaul Kocialkowski 
2259e43ccb0aSPaul Kocialkowski 	if (sensor->state.streaming) {
2260e43ccb0aSPaul Kocialkowski 		ret = -EBUSY;
2261e43ccb0aSPaul Kocialkowski 		goto complete;
2262e43ccb0aSPaul Kocialkowski 	}
2263e43ccb0aSPaul Kocialkowski 
2264e43ccb0aSPaul Kocialkowski 	/* Try to find requested mbus code. */
2265e43ccb0aSPaul Kocialkowski 	for (index = 0; index < ARRAY_SIZE(ov5648_mbus_codes); index++) {
2266e43ccb0aSPaul Kocialkowski 		if (ov5648_mbus_codes[index] == mbus_format->code) {
2267e43ccb0aSPaul Kocialkowski 			mbus_code = mbus_format->code;
2268e43ccb0aSPaul Kocialkowski 			break;
2269e43ccb0aSPaul Kocialkowski 		}
2270e43ccb0aSPaul Kocialkowski 	}
2271e43ccb0aSPaul Kocialkowski 
2272e43ccb0aSPaul Kocialkowski 	/* Fallback to default. */
2273e43ccb0aSPaul Kocialkowski 	if (!mbus_code)
2274e43ccb0aSPaul Kocialkowski 		mbus_code = ov5648_mbus_codes[0];
2275e43ccb0aSPaul Kocialkowski 
2276e43ccb0aSPaul Kocialkowski 	/* Find the mode with nearest dimensions. */
2277e43ccb0aSPaul Kocialkowski 	mode = v4l2_find_nearest_size(ov5648_modes, ARRAY_SIZE(ov5648_modes),
2278e43ccb0aSPaul Kocialkowski 				      output_size_x, output_size_y,
2279e43ccb0aSPaul Kocialkowski 				      mbus_format->width, mbus_format->height);
2280e43ccb0aSPaul Kocialkowski 	if (!mode) {
2281e43ccb0aSPaul Kocialkowski 		ret = -EINVAL;
2282e43ccb0aSPaul Kocialkowski 		goto complete;
2283e43ccb0aSPaul Kocialkowski 	}
2284e43ccb0aSPaul Kocialkowski 
2285e43ccb0aSPaul Kocialkowski 	ov5648_mbus_format_fill(mbus_format, mbus_code, mode);
2286e43ccb0aSPaul Kocialkowski 
2287e43ccb0aSPaul Kocialkowski 	if (format->which == V4L2_SUBDEV_FORMAT_TRY)
22880d346d2aSTomi Valkeinen 		*v4l2_subdev_get_try_format(subdev, sd_state, format->pad) =
2289e43ccb0aSPaul Kocialkowski 			*mbus_format;
2290e43ccb0aSPaul Kocialkowski 	else if (sensor->state.mode != mode ||
2291e43ccb0aSPaul Kocialkowski 		 sensor->state.mbus_code != mbus_code)
2292e43ccb0aSPaul Kocialkowski 		ret = ov5648_state_configure(sensor, mode, mbus_code);
2293e43ccb0aSPaul Kocialkowski 
2294e43ccb0aSPaul Kocialkowski complete:
2295e43ccb0aSPaul Kocialkowski 	mutex_unlock(&sensor->mutex);
2296e43ccb0aSPaul Kocialkowski 
2297e43ccb0aSPaul Kocialkowski 	return ret;
2298e43ccb0aSPaul Kocialkowski }
2299e43ccb0aSPaul Kocialkowski 
ov5648_enum_frame_size(struct v4l2_subdev * subdev,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_frame_size_enum * size_enum)2300e43ccb0aSPaul Kocialkowski static int ov5648_enum_frame_size(struct v4l2_subdev *subdev,
23010d346d2aSTomi Valkeinen 				  struct v4l2_subdev_state *sd_state,
2302e43ccb0aSPaul Kocialkowski 				  struct v4l2_subdev_frame_size_enum *size_enum)
2303e43ccb0aSPaul Kocialkowski {
2304e43ccb0aSPaul Kocialkowski 	const struct ov5648_mode *mode;
2305e43ccb0aSPaul Kocialkowski 
2306e43ccb0aSPaul Kocialkowski 	if (size_enum->index >= ARRAY_SIZE(ov5648_modes))
2307e43ccb0aSPaul Kocialkowski 		return -EINVAL;
2308e43ccb0aSPaul Kocialkowski 
2309e43ccb0aSPaul Kocialkowski 	mode = &ov5648_modes[size_enum->index];
2310e43ccb0aSPaul Kocialkowski 
2311e43ccb0aSPaul Kocialkowski 	size_enum->min_width = size_enum->max_width = mode->output_size_x;
2312e43ccb0aSPaul Kocialkowski 	size_enum->min_height = size_enum->max_height = mode->output_size_y;
2313e43ccb0aSPaul Kocialkowski 
2314e43ccb0aSPaul Kocialkowski 	return 0;
2315e43ccb0aSPaul Kocialkowski }
2316e43ccb0aSPaul Kocialkowski 
ov5648_enum_frame_interval(struct v4l2_subdev * subdev,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_frame_interval_enum * interval_enum)2317e43ccb0aSPaul Kocialkowski static int ov5648_enum_frame_interval(struct v4l2_subdev *subdev,
23180d346d2aSTomi Valkeinen 				      struct v4l2_subdev_state *sd_state,
2319e43ccb0aSPaul Kocialkowski 				      struct v4l2_subdev_frame_interval_enum *interval_enum)
2320e43ccb0aSPaul Kocialkowski {
2321e43ccb0aSPaul Kocialkowski 	const struct ov5648_mode *mode = NULL;
2322e43ccb0aSPaul Kocialkowski 	unsigned int mode_index;
2323e43ccb0aSPaul Kocialkowski 	unsigned int interval_index;
2324e43ccb0aSPaul Kocialkowski 
2325e43ccb0aSPaul Kocialkowski 	if (interval_enum->index > 0)
2326e43ccb0aSPaul Kocialkowski 		return -EINVAL;
2327e43ccb0aSPaul Kocialkowski 
2328e43ccb0aSPaul Kocialkowski 	/*
2329e43ccb0aSPaul Kocialkowski 	 * Multiple modes with the same dimensions may have different frame
2330e43ccb0aSPaul Kocialkowski 	 * intervals, so look up each relevant mode.
2331e43ccb0aSPaul Kocialkowski 	 */
2332e43ccb0aSPaul Kocialkowski 	for (mode_index = 0, interval_index = 0;
2333e43ccb0aSPaul Kocialkowski 	     mode_index < ARRAY_SIZE(ov5648_modes); mode_index++) {
2334e43ccb0aSPaul Kocialkowski 		mode = &ov5648_modes[mode_index];
2335e43ccb0aSPaul Kocialkowski 
2336e43ccb0aSPaul Kocialkowski 		if (mode->output_size_x == interval_enum->width &&
2337e43ccb0aSPaul Kocialkowski 		    mode->output_size_y == interval_enum->height) {
2338e43ccb0aSPaul Kocialkowski 			if (interval_index == interval_enum->index)
2339e43ccb0aSPaul Kocialkowski 				break;
2340e43ccb0aSPaul Kocialkowski 
2341e43ccb0aSPaul Kocialkowski 			interval_index++;
2342e43ccb0aSPaul Kocialkowski 		}
2343e43ccb0aSPaul Kocialkowski 	}
2344e43ccb0aSPaul Kocialkowski 
234538a50230SDan Carpenter 	if (mode_index == ARRAY_SIZE(ov5648_modes))
2346e43ccb0aSPaul Kocialkowski 		return -EINVAL;
2347e43ccb0aSPaul Kocialkowski 
2348e43ccb0aSPaul Kocialkowski 	switch (interval_enum->code) {
2349e43ccb0aSPaul Kocialkowski 	case MEDIA_BUS_FMT_SBGGR8_1X8:
2350e43ccb0aSPaul Kocialkowski 		interval_enum->interval = mode->frame_interval[0];
2351e43ccb0aSPaul Kocialkowski 		break;
2352e43ccb0aSPaul Kocialkowski 	case MEDIA_BUS_FMT_SBGGR10_1X10:
2353e43ccb0aSPaul Kocialkowski 		interval_enum->interval = mode->frame_interval[1];
2354e43ccb0aSPaul Kocialkowski 		break;
2355e43ccb0aSPaul Kocialkowski 	default:
2356e43ccb0aSPaul Kocialkowski 		return -EINVAL;
2357e43ccb0aSPaul Kocialkowski 	}
2358e43ccb0aSPaul Kocialkowski 
2359e43ccb0aSPaul Kocialkowski 	return 0;
2360e43ccb0aSPaul Kocialkowski }
2361e43ccb0aSPaul Kocialkowski 
2362e43ccb0aSPaul Kocialkowski static const struct v4l2_subdev_pad_ops ov5648_subdev_pad_ops = {
2363e43ccb0aSPaul Kocialkowski 	.enum_mbus_code		= ov5648_enum_mbus_code,
2364e43ccb0aSPaul Kocialkowski 	.get_fmt		= ov5648_get_fmt,
2365e43ccb0aSPaul Kocialkowski 	.set_fmt		= ov5648_set_fmt,
2366e43ccb0aSPaul Kocialkowski 	.enum_frame_size	= ov5648_enum_frame_size,
2367e43ccb0aSPaul Kocialkowski 	.enum_frame_interval	= ov5648_enum_frame_interval,
2368e43ccb0aSPaul Kocialkowski };
2369e43ccb0aSPaul Kocialkowski 
2370e43ccb0aSPaul Kocialkowski static const struct v4l2_subdev_ops ov5648_subdev_ops = {
2371e43ccb0aSPaul Kocialkowski 	.video		= &ov5648_subdev_video_ops,
2372e43ccb0aSPaul Kocialkowski 	.pad		= &ov5648_subdev_pad_ops,
2373e43ccb0aSPaul Kocialkowski };
2374e43ccb0aSPaul Kocialkowski 
ov5648_suspend(struct device * dev)2375e43ccb0aSPaul Kocialkowski static int ov5648_suspend(struct device *dev)
2376e43ccb0aSPaul Kocialkowski {
2377e43ccb0aSPaul Kocialkowski 	struct i2c_client *client = to_i2c_client(dev);
2378e43ccb0aSPaul Kocialkowski 	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
2379e43ccb0aSPaul Kocialkowski 	struct ov5648_sensor *sensor = ov5648_subdev_sensor(subdev);
2380e43ccb0aSPaul Kocialkowski 	struct ov5648_state *state = &sensor->state;
2381e43ccb0aSPaul Kocialkowski 	int ret = 0;
2382e43ccb0aSPaul Kocialkowski 
2383e43ccb0aSPaul Kocialkowski 	mutex_lock(&sensor->mutex);
2384e43ccb0aSPaul Kocialkowski 
2385e43ccb0aSPaul Kocialkowski 	if (state->streaming) {
2386e43ccb0aSPaul Kocialkowski 		ret = ov5648_sw_standby(sensor, true);
2387e43ccb0aSPaul Kocialkowski 		if (ret)
2388e43ccb0aSPaul Kocialkowski 			goto complete;
2389e43ccb0aSPaul Kocialkowski 	}
2390e43ccb0aSPaul Kocialkowski 
2391e43ccb0aSPaul Kocialkowski 	ret = ov5648_sensor_power(sensor, false);
2392e43ccb0aSPaul Kocialkowski 	if (ret)
2393e43ccb0aSPaul Kocialkowski 		ov5648_sw_standby(sensor, false);
2394e43ccb0aSPaul Kocialkowski 
2395e43ccb0aSPaul Kocialkowski complete:
2396e43ccb0aSPaul Kocialkowski 	mutex_unlock(&sensor->mutex);
2397e43ccb0aSPaul Kocialkowski 
2398e43ccb0aSPaul Kocialkowski 	return ret;
2399e43ccb0aSPaul Kocialkowski }
2400e43ccb0aSPaul Kocialkowski 
ov5648_resume(struct device * dev)2401e43ccb0aSPaul Kocialkowski static int ov5648_resume(struct device *dev)
2402e43ccb0aSPaul Kocialkowski {
2403e43ccb0aSPaul Kocialkowski 	struct i2c_client *client = to_i2c_client(dev);
2404e43ccb0aSPaul Kocialkowski 	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
2405e43ccb0aSPaul Kocialkowski 	struct ov5648_sensor *sensor = ov5648_subdev_sensor(subdev);
2406e43ccb0aSPaul Kocialkowski 	struct ov5648_state *state = &sensor->state;
2407e43ccb0aSPaul Kocialkowski 	int ret = 0;
2408e43ccb0aSPaul Kocialkowski 
2409e43ccb0aSPaul Kocialkowski 	mutex_lock(&sensor->mutex);
2410e43ccb0aSPaul Kocialkowski 
2411e43ccb0aSPaul Kocialkowski 	ret = ov5648_sensor_power(sensor, true);
2412e43ccb0aSPaul Kocialkowski 	if (ret)
2413e43ccb0aSPaul Kocialkowski 		goto complete;
2414e43ccb0aSPaul Kocialkowski 
2415e43ccb0aSPaul Kocialkowski 	ret = ov5648_sensor_init(sensor);
2416e43ccb0aSPaul Kocialkowski 	if (ret)
2417e43ccb0aSPaul Kocialkowski 		goto error_power;
2418e43ccb0aSPaul Kocialkowski 
2419e43ccb0aSPaul Kocialkowski 	ret = __v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
2420e43ccb0aSPaul Kocialkowski 	if (ret)
2421e43ccb0aSPaul Kocialkowski 		goto error_power;
2422e43ccb0aSPaul Kocialkowski 
2423e43ccb0aSPaul Kocialkowski 	if (state->streaming) {
2424e43ccb0aSPaul Kocialkowski 		ret = ov5648_sw_standby(sensor, false);
2425e43ccb0aSPaul Kocialkowski 		if (ret)
2426e43ccb0aSPaul Kocialkowski 			goto error_power;
2427e43ccb0aSPaul Kocialkowski 	}
2428e43ccb0aSPaul Kocialkowski 
2429e43ccb0aSPaul Kocialkowski 	goto complete;
2430e43ccb0aSPaul Kocialkowski 
2431e43ccb0aSPaul Kocialkowski error_power:
2432e43ccb0aSPaul Kocialkowski 	ov5648_sensor_power(sensor, false);
2433e43ccb0aSPaul Kocialkowski 
2434e43ccb0aSPaul Kocialkowski complete:
2435e43ccb0aSPaul Kocialkowski 	mutex_unlock(&sensor->mutex);
2436e43ccb0aSPaul Kocialkowski 
2437e43ccb0aSPaul Kocialkowski 	return ret;
2438e43ccb0aSPaul Kocialkowski }
2439e43ccb0aSPaul Kocialkowski 
ov5648_probe(struct i2c_client * client)2440e43ccb0aSPaul Kocialkowski static int ov5648_probe(struct i2c_client *client)
2441e43ccb0aSPaul Kocialkowski {
2442e43ccb0aSPaul Kocialkowski 	struct device *dev = &client->dev;
2443e43ccb0aSPaul Kocialkowski 	struct fwnode_handle *handle;
2444e43ccb0aSPaul Kocialkowski 	struct ov5648_sensor *sensor;
2445e43ccb0aSPaul Kocialkowski 	struct v4l2_subdev *subdev;
2446e43ccb0aSPaul Kocialkowski 	struct media_pad *pad;
2447e43ccb0aSPaul Kocialkowski 	unsigned long rate;
2448e43ccb0aSPaul Kocialkowski 	int ret;
2449e43ccb0aSPaul Kocialkowski 
2450e43ccb0aSPaul Kocialkowski 	sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
2451e43ccb0aSPaul Kocialkowski 	if (!sensor)
2452e43ccb0aSPaul Kocialkowski 		return -ENOMEM;
2453e43ccb0aSPaul Kocialkowski 
2454e43ccb0aSPaul Kocialkowski 	sensor->dev = dev;
2455e43ccb0aSPaul Kocialkowski 	sensor->i2c_client = client;
2456e43ccb0aSPaul Kocialkowski 
2457e43ccb0aSPaul Kocialkowski 	/* Graph Endpoint */
2458e43ccb0aSPaul Kocialkowski 
2459e43ccb0aSPaul Kocialkowski 	handle = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL);
2460e43ccb0aSPaul Kocialkowski 	if (!handle) {
2461ea12d248SColin Ian King 		dev_err(dev, "unable to find endpoint node\n");
2462e43ccb0aSPaul Kocialkowski 		return -EINVAL;
2463e43ccb0aSPaul Kocialkowski 	}
2464e43ccb0aSPaul Kocialkowski 
2465e43ccb0aSPaul Kocialkowski 	sensor->endpoint.bus_type = V4L2_MBUS_CSI2_DPHY;
2466e43ccb0aSPaul Kocialkowski 
2467e43ccb0aSPaul Kocialkowski 	ret = v4l2_fwnode_endpoint_alloc_parse(handle, &sensor->endpoint);
2468e43ccb0aSPaul Kocialkowski 	fwnode_handle_put(handle);
2469e43ccb0aSPaul Kocialkowski 	if (ret) {
2470e43ccb0aSPaul Kocialkowski 		dev_err(dev, "failed to parse endpoint node\n");
2471e43ccb0aSPaul Kocialkowski 		return ret;
2472e43ccb0aSPaul Kocialkowski 	}
2473e43ccb0aSPaul Kocialkowski 
2474e43ccb0aSPaul Kocialkowski 	/* GPIOs */
2475e43ccb0aSPaul Kocialkowski 
2476e43ccb0aSPaul Kocialkowski 	sensor->powerdown = devm_gpiod_get_optional(dev, "powerdown",
2477e43ccb0aSPaul Kocialkowski 						    GPIOD_OUT_HIGH);
2478e43ccb0aSPaul Kocialkowski 	if (IS_ERR(sensor->powerdown)) {
2479e43ccb0aSPaul Kocialkowski 		ret = PTR_ERR(sensor->powerdown);
2480e43ccb0aSPaul Kocialkowski 		goto error_endpoint;
2481e43ccb0aSPaul Kocialkowski 	}
2482e43ccb0aSPaul Kocialkowski 
2483e43ccb0aSPaul Kocialkowski 	sensor->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
2484e43ccb0aSPaul Kocialkowski 	if (IS_ERR(sensor->reset)) {
2485e43ccb0aSPaul Kocialkowski 		ret = PTR_ERR(sensor->reset);
2486e43ccb0aSPaul Kocialkowski 		goto error_endpoint;
2487e43ccb0aSPaul Kocialkowski 	}
2488e43ccb0aSPaul Kocialkowski 
2489e43ccb0aSPaul Kocialkowski 	/* Regulators */
2490e43ccb0aSPaul Kocialkowski 
2491e43ccb0aSPaul Kocialkowski 	/* DVDD: digital core */
2492e43ccb0aSPaul Kocialkowski 	sensor->dvdd = devm_regulator_get(dev, "dvdd");
2493e43ccb0aSPaul Kocialkowski 	if (IS_ERR(sensor->dvdd)) {
2494e43ccb0aSPaul Kocialkowski 		dev_err(dev, "cannot get DVDD (digital core) regulator\n");
2495e43ccb0aSPaul Kocialkowski 		ret = PTR_ERR(sensor->dvdd);
2496e43ccb0aSPaul Kocialkowski 		goto error_endpoint;
2497e43ccb0aSPaul Kocialkowski 	}
2498e43ccb0aSPaul Kocialkowski 
2499e43ccb0aSPaul Kocialkowski 	/* DOVDD: digital I/O */
2500e43ccb0aSPaul Kocialkowski 	sensor->dovdd = devm_regulator_get(dev, "dovdd");
2501a6dd5265SYang Yingliang 	if (IS_ERR(sensor->dovdd)) {
2502e43ccb0aSPaul Kocialkowski 		dev_err(dev, "cannot get DOVDD (digital I/O) regulator\n");
2503a6dd5265SYang Yingliang 		ret = PTR_ERR(sensor->dovdd);
2504e43ccb0aSPaul Kocialkowski 		goto error_endpoint;
2505e43ccb0aSPaul Kocialkowski 	}
2506e43ccb0aSPaul Kocialkowski 
2507e43ccb0aSPaul Kocialkowski 	/* AVDD: analog */
2508e43ccb0aSPaul Kocialkowski 	sensor->avdd = devm_regulator_get_optional(dev, "avdd");
2509e43ccb0aSPaul Kocialkowski 	if (IS_ERR(sensor->avdd)) {
2510e43ccb0aSPaul Kocialkowski 		dev_info(dev, "no AVDD regulator provided, using internal\n");
2511e43ccb0aSPaul Kocialkowski 		sensor->avdd = NULL;
2512e43ccb0aSPaul Kocialkowski 	}
2513e43ccb0aSPaul Kocialkowski 
2514e43ccb0aSPaul Kocialkowski 	/* External Clock */
2515e43ccb0aSPaul Kocialkowski 
2516e43ccb0aSPaul Kocialkowski 	sensor->xvclk = devm_clk_get(dev, NULL);
2517e43ccb0aSPaul Kocialkowski 	if (IS_ERR(sensor->xvclk)) {
2518e43ccb0aSPaul Kocialkowski 		dev_err(dev, "failed to get external clock\n");
2519e43ccb0aSPaul Kocialkowski 		ret = PTR_ERR(sensor->xvclk);
2520e43ccb0aSPaul Kocialkowski 		goto error_endpoint;
2521e43ccb0aSPaul Kocialkowski 	}
2522e43ccb0aSPaul Kocialkowski 
2523e43ccb0aSPaul Kocialkowski 	rate = clk_get_rate(sensor->xvclk);
2524e43ccb0aSPaul Kocialkowski 	if (rate != OV5648_XVCLK_RATE) {
2525e43ccb0aSPaul Kocialkowski 		dev_err(dev, "clock rate %lu Hz is unsupported\n", rate);
2526e43ccb0aSPaul Kocialkowski 		ret = -EINVAL;
2527e43ccb0aSPaul Kocialkowski 		goto error_endpoint;
2528e43ccb0aSPaul Kocialkowski 	}
2529e43ccb0aSPaul Kocialkowski 
2530e43ccb0aSPaul Kocialkowski 	/* Subdev, entity and pad */
2531e43ccb0aSPaul Kocialkowski 
2532e43ccb0aSPaul Kocialkowski 	subdev = &sensor->subdev;
2533e43ccb0aSPaul Kocialkowski 	v4l2_i2c_subdev_init(subdev, client, &ov5648_subdev_ops);
2534e43ccb0aSPaul Kocialkowski 
2535e43ccb0aSPaul Kocialkowski 	subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
2536e43ccb0aSPaul Kocialkowski 	subdev->entity.function = MEDIA_ENT_F_CAM_SENSOR;
2537e43ccb0aSPaul Kocialkowski 
2538e43ccb0aSPaul Kocialkowski 	pad = &sensor->pad;
2539e43ccb0aSPaul Kocialkowski 	pad->flags = MEDIA_PAD_FL_SOURCE;
2540e43ccb0aSPaul Kocialkowski 
2541e43ccb0aSPaul Kocialkowski 	ret = media_entity_pads_init(&subdev->entity, 1, pad);
2542e43ccb0aSPaul Kocialkowski 	if (ret)
2543e43ccb0aSPaul Kocialkowski 		goto error_entity;
2544e43ccb0aSPaul Kocialkowski 
2545e43ccb0aSPaul Kocialkowski 	/* Mutex */
2546e43ccb0aSPaul Kocialkowski 
2547e43ccb0aSPaul Kocialkowski 	mutex_init(&sensor->mutex);
2548e43ccb0aSPaul Kocialkowski 
2549e43ccb0aSPaul Kocialkowski 	/* Sensor */
2550e43ccb0aSPaul Kocialkowski 
2551e43ccb0aSPaul Kocialkowski 	ret = ov5648_ctrls_init(sensor);
2552e43ccb0aSPaul Kocialkowski 	if (ret)
2553e43ccb0aSPaul Kocialkowski 		goto error_mutex;
2554e43ccb0aSPaul Kocialkowski 
2555e43ccb0aSPaul Kocialkowski 	ret = ov5648_state_init(sensor);
2556e43ccb0aSPaul Kocialkowski 	if (ret)
2557e43ccb0aSPaul Kocialkowski 		goto error_ctrls;
2558e43ccb0aSPaul Kocialkowski 
2559e43ccb0aSPaul Kocialkowski 	/* Runtime PM */
2560e43ccb0aSPaul Kocialkowski 
2561e43ccb0aSPaul Kocialkowski 	pm_runtime_enable(sensor->dev);
2562e43ccb0aSPaul Kocialkowski 	pm_runtime_set_suspended(sensor->dev);
2563e43ccb0aSPaul Kocialkowski 
2564e43ccb0aSPaul Kocialkowski 	/* V4L2 subdev register */
2565e43ccb0aSPaul Kocialkowski 
256615786f7bSSakari Ailus 	ret = v4l2_async_register_subdev_sensor(subdev);
2567e43ccb0aSPaul Kocialkowski 	if (ret)
2568e43ccb0aSPaul Kocialkowski 		goto error_pm;
2569e43ccb0aSPaul Kocialkowski 
2570e43ccb0aSPaul Kocialkowski 	return 0;
2571e43ccb0aSPaul Kocialkowski 
2572e43ccb0aSPaul Kocialkowski error_pm:
2573e43ccb0aSPaul Kocialkowski 	pm_runtime_disable(sensor->dev);
2574e43ccb0aSPaul Kocialkowski 
2575e43ccb0aSPaul Kocialkowski error_ctrls:
2576e43ccb0aSPaul Kocialkowski 	v4l2_ctrl_handler_free(&sensor->ctrls.handler);
2577e43ccb0aSPaul Kocialkowski 
2578e43ccb0aSPaul Kocialkowski error_mutex:
2579e43ccb0aSPaul Kocialkowski 	mutex_destroy(&sensor->mutex);
2580e43ccb0aSPaul Kocialkowski 
2581e43ccb0aSPaul Kocialkowski error_entity:
2582e43ccb0aSPaul Kocialkowski 	media_entity_cleanup(&sensor->subdev.entity);
2583e43ccb0aSPaul Kocialkowski 
2584e43ccb0aSPaul Kocialkowski error_endpoint:
2585e43ccb0aSPaul Kocialkowski 	v4l2_fwnode_endpoint_free(&sensor->endpoint);
2586e43ccb0aSPaul Kocialkowski 
2587e43ccb0aSPaul Kocialkowski 	return ret;
2588e43ccb0aSPaul Kocialkowski }
2589e43ccb0aSPaul Kocialkowski 
ov5648_remove(struct i2c_client * client)2590ed5c2f5fSUwe Kleine-König static void ov5648_remove(struct i2c_client *client)
2591e43ccb0aSPaul Kocialkowski {
2592e43ccb0aSPaul Kocialkowski 	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
2593e43ccb0aSPaul Kocialkowski 	struct ov5648_sensor *sensor = ov5648_subdev_sensor(subdev);
2594e43ccb0aSPaul Kocialkowski 
2595e43ccb0aSPaul Kocialkowski 	v4l2_async_unregister_subdev(subdev);
2596e43ccb0aSPaul Kocialkowski 	pm_runtime_disable(sensor->dev);
2597e43ccb0aSPaul Kocialkowski 	v4l2_ctrl_handler_free(&sensor->ctrls.handler);
2598e43ccb0aSPaul Kocialkowski 	mutex_destroy(&sensor->mutex);
2599e43ccb0aSPaul Kocialkowski 	media_entity_cleanup(&subdev->entity);
2600c95770e4SRafael Mendonca 	v4l2_fwnode_endpoint_free(&sensor->endpoint);
2601e43ccb0aSPaul Kocialkowski }
2602e43ccb0aSPaul Kocialkowski 
2603e43ccb0aSPaul Kocialkowski static const struct dev_pm_ops ov5648_pm_ops = {
2604e43ccb0aSPaul Kocialkowski 	SET_RUNTIME_PM_OPS(ov5648_suspend, ov5648_resume, NULL)
2605e43ccb0aSPaul Kocialkowski };
2606e43ccb0aSPaul Kocialkowski 
2607e43ccb0aSPaul Kocialkowski static const struct of_device_id ov5648_of_match[] = {
2608e43ccb0aSPaul Kocialkowski 	{ .compatible = "ovti,ov5648" },
2609e43ccb0aSPaul Kocialkowski 	{ }
2610e43ccb0aSPaul Kocialkowski };
2611e43ccb0aSPaul Kocialkowski MODULE_DEVICE_TABLE(of, ov5648_of_match);
2612e43ccb0aSPaul Kocialkowski 
2613e43ccb0aSPaul Kocialkowski static struct i2c_driver ov5648_driver = {
2614e43ccb0aSPaul Kocialkowski 	.driver = {
2615e43ccb0aSPaul Kocialkowski 		.name = "ov5648",
2616e43ccb0aSPaul Kocialkowski 		.of_match_table = ov5648_of_match,
2617e43ccb0aSPaul Kocialkowski 		.pm = &ov5648_pm_ops,
2618e43ccb0aSPaul Kocialkowski 	},
2619*aaeb31c0SUwe Kleine-König 	.probe = ov5648_probe,
2620e43ccb0aSPaul Kocialkowski 	.remove = ov5648_remove,
2621e43ccb0aSPaul Kocialkowski };
2622e43ccb0aSPaul Kocialkowski 
2623e43ccb0aSPaul Kocialkowski module_i2c_driver(ov5648_driver);
2624e43ccb0aSPaul Kocialkowski 
2625e43ccb0aSPaul Kocialkowski MODULE_AUTHOR("Paul Kocialkowski <paul.kocialkowski@bootlin.com>");
2626e43ccb0aSPaul Kocialkowski MODULE_DESCRIPTION("V4L2 driver for the OmniVision OV5648 image sensor");
2627e43ccb0aSPaul Kocialkowski MODULE_LICENSE("GPL v2");
2628