1 | // SPDX-License-Identifier: GPL-2.0-only |
---|---|
2 | /* |
3 | * mt9m114.c onsemi MT9M114 sensor driver |
4 | * |
5 | * Copyright (c) 2020-2023 Laurent Pinchart <laurent.pinchart@ideasonboard.com> |
6 | * Copyright (c) 2012 Analog Devices Inc. |
7 | * |
8 | * Almost complete rewrite of work by Scott Jiang <Scott.Jiang.Linux@gmail.com> |
9 | * itself based on work from Andrew Chew <achew@nvidia.com>. |
10 | */ |
11 | |
12 | #include <linux/clk.h> |
13 | #include <linux/delay.h> |
14 | #include <linux/errno.h> |
15 | #include <linux/gpio/consumer.h> |
16 | #include <linux/i2c.h> |
17 | #include <linux/mod_devicetable.h> |
18 | #include <linux/module.h> |
19 | #include <linux/mutex.h> |
20 | #include <linux/pm_runtime.h> |
21 | #include <linux/regmap.h> |
22 | #include <linux/regulator/consumer.h> |
23 | #include <linux/types.h> |
24 | #include <linux/videodev2.h> |
25 | |
26 | #include <media/v4l2-async.h> |
27 | #include <media/v4l2-cci.h> |
28 | #include <media/v4l2-ctrls.h> |
29 | #include <media/v4l2-device.h> |
30 | #include <media/v4l2-fwnode.h> |
31 | #include <media/v4l2-mediabus.h> |
32 | #include <media/v4l2-subdev.h> |
33 | |
34 | /* Sysctl registers */ |
35 | #define MT9M114_CHIP_ID CCI_REG16(0x0000) |
36 | #define MT9M114_COMMAND_REGISTER CCI_REG16(0x0080) |
37 | #define MT9M114_COMMAND_REGISTER_APPLY_PATCH BIT(0) |
38 | #define MT9M114_COMMAND_REGISTER_SET_STATE BIT(1) |
39 | #define MT9M114_COMMAND_REGISTER_REFRESH BIT(2) |
40 | #define MT9M114_COMMAND_REGISTER_WAIT_FOR_EVENT BIT(3) |
41 | #define MT9M114_COMMAND_REGISTER_OK BIT(15) |
42 | #define MT9M114_RESET_AND_MISC_CONTROL CCI_REG16(0x001a) |
43 | #define MT9M114_RESET_SOC BIT(0) |
44 | #define MT9M114_PAD_SLEW CCI_REG16(0x001e) |
45 | #define MT9M114_PAD_CONTROL CCI_REG16(0x0032) |
46 | |
47 | /* XDMA registers */ |
48 | #define MT9M114_ACCESS_CTL_STAT CCI_REG16(0x0982) |
49 | #define MT9M114_PHYSICAL_ADDRESS_ACCESS CCI_REG16(0x098a) |
50 | #define MT9M114_LOGICAL_ADDRESS_ACCESS CCI_REG16(0x098e) |
51 | |
52 | /* Sensor Core registers */ |
53 | #define MT9M114_COARSE_INTEGRATION_TIME CCI_REG16(0x3012) |
54 | #define MT9M114_FINE_INTEGRATION_TIME CCI_REG16(0x3014) |
55 | #define MT9M114_RESET_REGISTER CCI_REG16(0x301a) |
56 | #define MT9M114_RESET_REGISTER_LOCK_REG BIT(3) |
57 | #define MT9M114_RESET_REGISTER_MASK_BAD BIT(9) |
58 | #define MT9M114_FLASH CCI_REG16(0x3046) |
59 | #define MT9M114_GREEN1_GAIN CCI_REG16(0x3056) |
60 | #define MT9M114_BLUE_GAIN CCI_REG16(0x3058) |
61 | #define MT9M114_RED_GAIN CCI_REG16(0x305a) |
62 | #define MT9M114_GREEN2_GAIN CCI_REG16(0x305c) |
63 | #define MT9M114_GLOBAL_GAIN CCI_REG16(0x305e) |
64 | #define MT9M114_GAIN_DIGITAL_GAIN(n) ((n) << 12) |
65 | #define MT9M114_GAIN_DIGITAL_GAIN_MASK (0xf << 12) |
66 | #define MT9M114_GAIN_ANALOG_GAIN(n) ((n) << 0) |
67 | #define MT9M114_GAIN_ANALOG_GAIN_MASK (0xff << 0) |
68 | #define MT9M114_CUSTOMER_REV CCI_REG16(0x31fe) |
69 | |
70 | /* Monitor registers */ |
71 | #define MT9M114_MON_MAJOR_VERSION CCI_REG16(0x8000) |
72 | #define MT9M114_MON_MINOR_VERSION CCI_REG16(0x8002) |
73 | #define MT9M114_MON_RELEASE_VERSION CCI_REG16(0x8004) |
74 | |
75 | /* Auto-Exposure Track registers */ |
76 | #define MT9M114_AE_TRACK_ALGO CCI_REG16(0xa804) |
77 | #define MT9M114_AE_TRACK_EXEC_AUTOMATIC_EXPOSURE BIT(0) |
78 | #define MT9M114_AE_TRACK_AE_TRACKING_DAMPENING_SPEED CCI_REG8(0xa80a) |
79 | |
80 | /* Color Correction Matrix registers */ |
81 | #define MT9M114_CCM_ALGO CCI_REG16(0xb404) |
82 | #define MT9M114_CCM_EXEC_CALC_CCM_MATRIX BIT(4) |
83 | #define MT9M114_CCM_DELTA_GAIN CCI_REG8(0xb42a) |
84 | |
85 | /* Camera Control registers */ |
86 | #define MT9M114_CAM_SENSOR_CFG_Y_ADDR_START CCI_REG16(0xc800) |
87 | #define MT9M114_CAM_SENSOR_CFG_X_ADDR_START CCI_REG16(0xc802) |
88 | #define MT9M114_CAM_SENSOR_CFG_Y_ADDR_END CCI_REG16(0xc804) |
89 | #define MT9M114_CAM_SENSOR_CFG_X_ADDR_END CCI_REG16(0xc806) |
90 | #define MT9M114_CAM_SENSOR_CFG_PIXCLK CCI_REG32(0xc808) |
91 | #define MT9M114_CAM_SENSOR_CFG_ROW_SPEED CCI_REG16(0xc80c) |
92 | #define MT9M114_CAM_SENSOR_CFG_FINE_INTEG_TIME_MIN CCI_REG16(0xc80e) |
93 | #define MT9M114_CAM_SENSOR_CFG_FINE_INTEG_TIME_MAX CCI_REG16(0xc810) |
94 | #define MT9M114_CAM_SENSOR_CFG_FRAME_LENGTH_LINES CCI_REG16(0xc812) |
95 | #define MT9M114_CAM_SENSOR_CFG_FRAME_LENGTH_LINES_MAX 65535 |
96 | #define MT9M114_CAM_SENSOR_CFG_LINE_LENGTH_PCK CCI_REG16(0xc814) |
97 | #define MT9M114_CAM_SENSOR_CFG_LINE_LENGTH_PCK_MAX 8191 |
98 | #define MT9M114_CAM_SENSOR_CFG_FINE_CORRECTION CCI_REG16(0xc816) |
99 | #define MT9M114_CAM_SENSOR_CFG_CPIPE_LAST_ROW CCI_REG16(0xc818) |
100 | #define MT9M114_CAM_SENSOR_CFG_REG_0_DATA CCI_REG16(0xc826) |
101 | #define MT9M114_CAM_SENSOR_CONTROL_READ_MODE CCI_REG16(0xc834) |
102 | #define MT9M114_CAM_SENSOR_CONTROL_HORZ_MIRROR_EN BIT(0) |
103 | #define MT9M114_CAM_SENSOR_CONTROL_VERT_FLIP_EN BIT(1) |
104 | #define MT9M114_CAM_SENSOR_CONTROL_X_READ_OUT_NORMAL (0 << 4) |
105 | #define MT9M114_CAM_SENSOR_CONTROL_X_READ_OUT_SKIPPING (1 << 4) |
106 | #define MT9M114_CAM_SENSOR_CONTROL_X_READ_OUT_AVERAGE (2 << 4) |
107 | #define MT9M114_CAM_SENSOR_CONTROL_X_READ_OUT_SUMMING (3 << 4) |
108 | #define MT9M114_CAM_SENSOR_CONTROL_X_READ_OUT_MASK (3 << 4) |
109 | #define MT9M114_CAM_SENSOR_CONTROL_Y_READ_OUT_NORMAL (0 << 8) |
110 | #define MT9M114_CAM_SENSOR_CONTROL_Y_READ_OUT_SKIPPING (1 << 8) |
111 | #define MT9M114_CAM_SENSOR_CONTROL_Y_READ_OUT_SUMMING (3 << 8) |
112 | #define MT9M114_CAM_SENSOR_CONTROL_Y_READ_OUT_MASK (3 << 8) |
113 | #define MT9M114_CAM_SENSOR_CONTROL_ANALOG_GAIN CCI_REG16(0xc836) |
114 | #define MT9M114_CAM_SENSOR_CONTROL_COARSE_INTEGRATION_TIME CCI_REG16(0xc83c) |
115 | #define MT9M114_CAM_SENSOR_CONTROL_FINE_INTEGRATION_TIME CCI_REG16(0xc83e) |
116 | #define MT9M114_CAM_MODE_SELECT CCI_REG8(0xc84c) |
117 | #define MT9M114_CAM_MODE_SELECT_NORMAL (0 << 0) |
118 | #define MT9M114_CAM_MODE_SELECT_LENS_CALIBRATION (1 << 0) |
119 | #define MT9M114_CAM_MODE_SELECT_TEST_PATTERN (2 << 0) |
120 | #define MT9M114_CAM_MODE_TEST_PATTERN_SELECT CCI_REG8(0xc84d) |
121 | #define MT9M114_CAM_MODE_TEST_PATTERN_SELECT_SOLID (1 << 0) |
122 | #define MT9M114_CAM_MODE_TEST_PATTERN_SELECT_SOLID_BARS (4 << 0) |
123 | #define MT9M114_CAM_MODE_TEST_PATTERN_SELECT_RANDOM (5 << 0) |
124 | #define MT9M114_CAM_MODE_TEST_PATTERN_SELECT_FADING_BARS (8 << 0) |
125 | #define MT9M114_CAM_MODE_TEST_PATTERN_SELECT_WALKING_1S_10B (10 << 0) |
126 | #define MT9M114_CAM_MODE_TEST_PATTERN_SELECT_WALKING_1S_8B (11 << 0) |
127 | #define MT9M114_CAM_MODE_TEST_PATTERN_RED CCI_REG16(0xc84e) |
128 | #define MT9M114_CAM_MODE_TEST_PATTERN_GREEN CCI_REG16(0xc850) |
129 | #define MT9M114_CAM_MODE_TEST_PATTERN_BLUE CCI_REG16(0xc852) |
130 | #define MT9M114_CAM_CROP_WINDOW_XOFFSET CCI_REG16(0xc854) |
131 | #define MT9M114_CAM_CROP_WINDOW_YOFFSET CCI_REG16(0xc856) |
132 | #define MT9M114_CAM_CROP_WINDOW_WIDTH CCI_REG16(0xc858) |
133 | #define MT9M114_CAM_CROP_WINDOW_HEIGHT CCI_REG16(0xc85a) |
134 | #define MT9M114_CAM_CROP_CROPMODE CCI_REG8(0xc85c) |
135 | #define MT9M114_CAM_CROP_MODE_AE_AUTO_CROP_EN BIT(0) |
136 | #define MT9M114_CAM_CROP_MODE_AWB_AUTO_CROP_EN BIT(1) |
137 | #define MT9M114_CAM_OUTPUT_WIDTH CCI_REG16(0xc868) |
138 | #define MT9M114_CAM_OUTPUT_HEIGHT CCI_REG16(0xc86a) |
139 | #define MT9M114_CAM_OUTPUT_FORMAT CCI_REG16(0xc86c) |
140 | #define MT9M114_CAM_OUTPUT_FORMAT_SWAP_RED_BLUE BIT(0) |
141 | #define MT9M114_CAM_OUTPUT_FORMAT_SWAP_BYTES BIT(1) |
142 | #define MT9M114_CAM_OUTPUT_FORMAT_MONO_ENABLE BIT(2) |
143 | #define MT9M114_CAM_OUTPUT_FORMAT_BT656_ENABLE BIT(3) |
144 | #define MT9M114_CAM_OUTPUT_FORMAT_BT656_CROP_SCALE_DISABLE BIT(4) |
145 | #define MT9M114_CAM_OUTPUT_FORMAT_FVLV_DISABLE BIT(5) |
146 | #define MT9M114_CAM_OUTPUT_FORMAT_FORMAT_YUV (0 << 8) |
147 | #define MT9M114_CAM_OUTPUT_FORMAT_FORMAT_RGB (1 << 8) |
148 | #define MT9M114_CAM_OUTPUT_FORMAT_FORMAT_BAYER (2 << 8) |
149 | #define MT9M114_CAM_OUTPUT_FORMAT_FORMAT_NONE (3 << 8) |
150 | #define MT9M114_CAM_OUTPUT_FORMAT_FORMAT_MASK (3 << 8) |
151 | #define MT9M114_CAM_OUTPUT_FORMAT_BAYER_FORMAT_RAWR10 (0 << 10) |
152 | #define MT9M114_CAM_OUTPUT_FORMAT_BAYER_FORMAT_PRELSC_8_2 (1 << 10) |
153 | #define MT9M114_CAM_OUTPUT_FORMAT_BAYER_FORMAT_POSTLSC_8_2 (2 << 10) |
154 | #define MT9M114_CAM_OUTPUT_FORMAT_BAYER_FORMAT_PROCESSED8 (3 << 10) |
155 | #define MT9M114_CAM_OUTPUT_FORMAT_BAYER_FORMAT_MASK (3 << 10) |
156 | #define MT9M114_CAM_OUTPUT_FORMAT_RGB_FORMAT_565RGB (0 << 12) |
157 | #define MT9M114_CAM_OUTPUT_FORMAT_RGB_FORMAT_555RGB (1 << 12) |
158 | #define MT9M114_CAM_OUTPUT_FORMAT_RGB_FORMAT_444xRGB (2 << 12) |
159 | #define MT9M114_CAM_OUTPUT_FORMAT_RGB_FORMAT_444RGBx (3 << 12) |
160 | #define MT9M114_CAM_OUTPUT_FORMAT_RGB_FORMAT_MASK (3 << 12) |
161 | #define MT9M114_CAM_OUTPUT_FORMAT_YUV CCI_REG16(0xc86e) |
162 | #define MT9M114_CAM_OUTPUT_FORMAT_YUV_CLIP BIT(5) |
163 | #define MT9M114_CAM_OUTPUT_FORMAT_YUV_AUV_OFFSET BIT(4) |
164 | #define MT9M114_CAM_OUTPUT_FORMAT_YUV_SELECT_601 BIT(3) |
165 | #define MT9M114_CAM_OUTPUT_FORMAT_YUV_NORMALISE BIT(2) |
166 | #define MT9M114_CAM_OUTPUT_FORMAT_YUV_SAMPLING_EVEN_UV (0 << 0) |
167 | #define MT9M114_CAM_OUTPUT_FORMAT_YUV_SAMPLING_ODD_UV (1 << 0) |
168 | #define MT9M114_CAM_OUTPUT_FORMAT_YUV_SAMPLING_EVENU_ODDV (2 << 0) |
169 | #define MT9M114_CAM_OUTPUT_Y_OFFSET CCI_REG8(0xc870) |
170 | #define MT9M114_CAM_AET_AEMODE CCI_REG8(0xc878) |
171 | #define MT9M114_CAM_AET_EXEC_SET_INDOOR BIT(0) |
172 | #define MT9M114_CAM_AET_DISCRETE_FRAMERATE BIT(1) |
173 | #define MT9M114_CAM_AET_ADAPTATIVE_TARGET_LUMA BIT(2) |
174 | #define MT9M114_CAM_AET_ADAPTATIVE_SKIP_FRAMES BIT(3) |
175 | #define MT9M114_CAM_AET_SKIP_FRAMES CCI_REG8(0xc879) |
176 | #define MT9M114_CAM_AET_TARGET_AVERAGE_LUMA CCI_REG8(0xc87a) |
177 | #define MT9M114_CAM_AET_TARGET_AVERAGE_LUMA_DARK CCI_REG8(0xc87b) |
178 | #define MT9M114_CAM_AET_BLACK_CLIPPING_TARGET CCI_REG16(0xc87c) |
179 | #define MT9M114_CAM_AET_AE_MIN_VIRT_INT_TIME_PCLK CCI_REG16(0xc87e) |
180 | #define MT9M114_CAM_AET_AE_MIN_VIRT_DGAIN CCI_REG16(0xc880) |
181 | #define MT9M114_CAM_AET_AE_MAX_VIRT_DGAIN CCI_REG16(0xc882) |
182 | #define MT9M114_CAM_AET_AE_MIN_VIRT_AGAIN CCI_REG16(0xc884) |
183 | #define MT9M114_CAM_AET_AE_MAX_VIRT_AGAIN CCI_REG16(0xc886) |
184 | #define MT9M114_CAM_AET_AE_VIRT_GAIN_TH_EG CCI_REG16(0xc888) |
185 | #define MT9M114_CAM_AET_AE_EG_GATE_PERCENTAGE CCI_REG8(0xc88a) |
186 | #define MT9M114_CAM_AET_FLICKER_FREQ_HZ CCI_REG8(0xc88b) |
187 | #define MT9M114_CAM_AET_MAX_FRAME_RATE CCI_REG16(0xc88c) |
188 | #define MT9M114_CAM_AET_MIN_FRAME_RATE CCI_REG16(0xc88e) |
189 | #define MT9M114_CAM_AET_TARGET_GAIN CCI_REG16(0xc890) |
190 | #define MT9M114_CAM_AWB_CCM_L(n) CCI_REG16(0xc892 + (n) * 2) |
191 | #define MT9M114_CAM_AWB_CCM_M(n) CCI_REG16(0xc8a4 + (n) * 2) |
192 | #define MT9M114_CAM_AWB_CCM_R(n) CCI_REG16(0xc8b6 + (n) * 2) |
193 | #define MT9M114_CAM_AWB_CCM_L_RG_GAIN CCI_REG16(0xc8c8) |
194 | #define MT9M114_CAM_AWB_CCM_L_BG_GAIN CCI_REG16(0xc8ca) |
195 | #define MT9M114_CAM_AWB_CCM_M_RG_GAIN CCI_REG16(0xc8cc) |
196 | #define MT9M114_CAM_AWB_CCM_M_BG_GAIN CCI_REG16(0xc8ce) |
197 | #define MT9M114_CAM_AWB_CCM_R_RG_GAIN CCI_REG16(0xc8d0) |
198 | #define MT9M114_CAM_AWB_CCM_R_BG_GAIN CCI_REG16(0xc8d2) |
199 | #define MT9M114_CAM_AWB_CCM_L_CTEMP CCI_REG16(0xc8d4) |
200 | #define MT9M114_CAM_AWB_CCM_M_CTEMP CCI_REG16(0xc8d6) |
201 | #define MT9M114_CAM_AWB_CCM_R_CTEMP CCI_REG16(0xc8d8) |
202 | #define MT9M114_CAM_AWB_AWB_XSCALE CCI_REG8(0xc8f2) |
203 | #define MT9M114_CAM_AWB_AWB_YSCALE CCI_REG8(0xc8f3) |
204 | #define MT9M114_CAM_AWB_AWB_WEIGHTS(n) CCI_REG16(0xc8f4 + (n) * 2) |
205 | #define MT9M114_CAM_AWB_AWB_XSHIFT_PRE_ADJ CCI_REG16(0xc904) |
206 | #define MT9M114_CAM_AWB_AWB_YSHIFT_PRE_ADJ CCI_REG16(0xc906) |
207 | #define MT9M114_CAM_AWB_AWBMODE CCI_REG8(0xc909) |
208 | #define MT9M114_CAM_AWB_MODE_AUTO BIT(1) |
209 | #define MT9M114_CAM_AWB_MODE_EXCLUSIVE_AE BIT(0) |
210 | #define MT9M114_CAM_AWB_K_R_L CCI_REG8(0xc90c) |
211 | #define MT9M114_CAM_AWB_K_G_L CCI_REG8(0xc90d) |
212 | #define MT9M114_CAM_AWB_K_B_L CCI_REG8(0xc90e) |
213 | #define MT9M114_CAM_AWB_K_R_R CCI_REG8(0xc90f) |
214 | #define MT9M114_CAM_AWB_K_G_R CCI_REG8(0xc910) |
215 | #define MT9M114_CAM_AWB_K_B_R CCI_REG8(0xc911) |
216 | #define MT9M114_CAM_STAT_AWB_CLIP_WINDOW_XSTART CCI_REG16(0xc914) |
217 | #define MT9M114_CAM_STAT_AWB_CLIP_WINDOW_YSTART CCI_REG16(0xc916) |
218 | #define MT9M114_CAM_STAT_AWB_CLIP_WINDOW_XEND CCI_REG16(0xc918) |
219 | #define MT9M114_CAM_STAT_AWB_CLIP_WINDOW_YEND CCI_REG16(0xc91a) |
220 | #define MT9M114_CAM_STAT_AE_INITIAL_WINDOW_XSTART CCI_REG16(0xc91c) |
221 | #define MT9M114_CAM_STAT_AE_INITIAL_WINDOW_YSTART CCI_REG16(0xc91e) |
222 | #define MT9M114_CAM_STAT_AE_INITIAL_WINDOW_XEND CCI_REG16(0xc920) |
223 | #define MT9M114_CAM_STAT_AE_INITIAL_WINDOW_YEND CCI_REG16(0xc922) |
224 | #define MT9M114_CAM_LL_LLMODE CCI_REG16(0xc924) |
225 | #define MT9M114_CAM_LL_START_BRIGHTNESS CCI_REG16(0xc926) |
226 | #define MT9M114_CAM_LL_STOP_BRIGHTNESS CCI_REG16(0xc928) |
227 | #define MT9M114_CAM_LL_START_SATURATION CCI_REG8(0xc92a) |
228 | #define MT9M114_CAM_LL_END_SATURATION CCI_REG8(0xc92b) |
229 | #define MT9M114_CAM_LL_START_DESATURATION CCI_REG8(0xc92c) |
230 | #define MT9M114_CAM_LL_END_DESATURATION CCI_REG8(0xc92d) |
231 | #define MT9M114_CAM_LL_START_DEMOSAICING CCI_REG8(0xc92e) |
232 | #define MT9M114_CAM_LL_START_AP_GAIN CCI_REG8(0xc92f) |
233 | #define MT9M114_CAM_LL_START_AP_THRESH CCI_REG8(0xc930) |
234 | #define MT9M114_CAM_LL_STOP_DEMOSAICING CCI_REG8(0xc931) |
235 | #define MT9M114_CAM_LL_STOP_AP_GAIN CCI_REG8(0xc932) |
236 | #define MT9M114_CAM_LL_STOP_AP_THRESH CCI_REG8(0xc933) |
237 | #define MT9M114_CAM_LL_START_NR_RED CCI_REG8(0xc934) |
238 | #define MT9M114_CAM_LL_START_NR_GREEN CCI_REG8(0xc935) |
239 | #define MT9M114_CAM_LL_START_NR_BLUE CCI_REG8(0xc936) |
240 | #define MT9M114_CAM_LL_START_NR_THRESH CCI_REG8(0xc937) |
241 | #define MT9M114_CAM_LL_STOP_NR_RED CCI_REG8(0xc938) |
242 | #define MT9M114_CAM_LL_STOP_NR_GREEN CCI_REG8(0xc939) |
243 | #define MT9M114_CAM_LL_STOP_NR_BLUE CCI_REG8(0xc93a) |
244 | #define MT9M114_CAM_LL_STOP_NR_THRESH CCI_REG8(0xc93b) |
245 | #define MT9M114_CAM_LL_START_CONTRAST_BM CCI_REG16(0xc93c) |
246 | #define MT9M114_CAM_LL_STOP_CONTRAST_BM CCI_REG16(0xc93e) |
247 | #define MT9M114_CAM_LL_GAMMA CCI_REG16(0xc940) |
248 | #define MT9M114_CAM_LL_START_CONTRAST_GRADIENT CCI_REG8(0xc942) |
249 | #define MT9M114_CAM_LL_STOP_CONTRAST_GRADIENT CCI_REG8(0xc943) |
250 | #define MT9M114_CAM_LL_START_CONTRAST_LUMA_PERCENTAGE CCI_REG8(0xc944) |
251 | #define MT9M114_CAM_LL_STOP_CONTRAST_LUMA_PERCENTAGE CCI_REG8(0xc945) |
252 | #define MT9M114_CAM_LL_START_GAIN_METRIC CCI_REG16(0xc946) |
253 | #define MT9M114_CAM_LL_STOP_GAIN_METRIC CCI_REG16(0xc948) |
254 | #define MT9M114_CAM_LL_START_FADE_TO_BLACK_LUMA CCI_REG16(0xc94a) |
255 | #define MT9M114_CAM_LL_STOP_FADE_TO_BLACK_LUMA CCI_REG16(0xc94c) |
256 | #define MT9M114_CAM_LL_CLUSTER_DC_TH_BM CCI_REG16(0xc94e) |
257 | #define MT9M114_CAM_LL_CLUSTER_DC_GATE_PERCENTAGE CCI_REG8(0xc950) |
258 | #define MT9M114_CAM_LL_SUMMING_SENSITIVITY_FACTOR CCI_REG8(0xc951) |
259 | #define MT9M114_CAM_LL_START_TARGET_LUMA_BM CCI_REG16(0xc952) |
260 | #define MT9M114_CAM_LL_STOP_TARGET_LUMA_BM CCI_REG16(0xc954) |
261 | #define MT9M114_CAM_PGA_PGA_CONTROL CCI_REG16(0xc95e) |
262 | #define MT9M114_CAM_SYSCTL_PLL_ENABLE CCI_REG8(0xc97e) |
263 | #define MT9M114_CAM_SYSCTL_PLL_ENABLE_VALUE BIT(0) |
264 | #define MT9M114_CAM_SYSCTL_PLL_DIVIDER_M_N CCI_REG16(0xc980) |
265 | #define MT9M114_CAM_SYSCTL_PLL_DIVIDER_VALUE(m, n) (((n) << 8) | (m)) |
266 | #define MT9M114_CAM_SYSCTL_PLL_DIVIDER_P CCI_REG16(0xc982) |
267 | #define MT9M114_CAM_SYSCTL_PLL_DIVIDER_P_VALUE(p) ((p) << 8) |
268 | #define MT9M114_CAM_PORT_OUTPUT_CONTROL CCI_REG16(0xc984) |
269 | #define MT9M114_CAM_PORT_PORT_SELECT_PARALLEL (0 << 0) |
270 | #define MT9M114_CAM_PORT_PORT_SELECT_MIPI (1 << 0) |
271 | #define MT9M114_CAM_PORT_CLOCK_SLOWDOWN BIT(3) |
272 | #define MT9M114_CAM_PORT_TRUNCATE_RAW_BAYER BIT(4) |
273 | #define MT9M114_CAM_PORT_PIXCLK_GATE BIT(5) |
274 | #define MT9M114_CAM_PORT_CONT_MIPI_CLK BIT(6) |
275 | #define MT9M114_CAM_PORT_CHAN_NUM(vc) ((vc) << 8) |
276 | #define MT9M114_CAM_PORT_MIPI_TIMING_T_HS_ZERO CCI_REG16(0xc988) |
277 | #define MT9M114_CAM_PORT_MIPI_TIMING_T_HS_ZERO_VALUE(n) ((n) << 8) |
278 | #define MT9M114_CAM_PORT_MIPI_TIMING_T_HS_EXIT_TRAIL CCI_REG16(0xc98a) |
279 | #define MT9M114_CAM_PORT_MIPI_TIMING_T_HS_EXIT_VALUE(n) ((n) << 8) |
280 | #define MT9M114_CAM_PORT_MIPI_TIMING_T_HS_TRAIL_VALUE(n) ((n) << 0) |
281 | #define MT9M114_CAM_PORT_MIPI_TIMING_T_CLK_POST_PRE CCI_REG16(0xc98c) |
282 | #define MT9M114_CAM_PORT_MIPI_TIMING_T_CLK_POST_VALUE(n) ((n) << 8) |
283 | #define MT9M114_CAM_PORT_MIPI_TIMING_T_CLK_PRE_VALUE(n) ((n) << 0) |
284 | #define MT9M114_CAM_PORT_MIPI_TIMING_T_CLK_TRAIL_ZERO CCI_REG16(0xc98e) |
285 | #define MT9M114_CAM_PORT_MIPI_TIMING_T_CLK_TRAIL_VALUE(n) ((n) << 8) |
286 | #define MT9M114_CAM_PORT_MIPI_TIMING_T_CLK_ZERO_VALUE(n) ((n) << 0) |
287 | |
288 | /* System Manager registers */ |
289 | #define MT9M114_SYSMGR_NEXT_STATE CCI_REG8(0xdc00) |
290 | #define MT9M114_SYSMGR_CURRENT_STATE CCI_REG8(0xdc01) |
291 | #define MT9M114_SYSMGR_CMD_STATUS CCI_REG8(0xdc02) |
292 | |
293 | /* Patch Loader registers */ |
294 | #define MT9M114_PATCHLDR_LOADER_ADDRESS CCI_REG16(0xe000) |
295 | #define MT9M114_PATCHLDR_PATCH_ID CCI_REG16(0xe002) |
296 | #define MT9M114_PATCHLDR_FIRMWARE_ID CCI_REG32(0xe004) |
297 | #define MT9M114_PATCHLDR_APPLY_STATUS CCI_REG8(0xe008) |
298 | #define MT9M114_PATCHLDR_NUM_PATCHES CCI_REG8(0xe009) |
299 | #define MT9M114_PATCHLDR_PATCH_ID_0 CCI_REG16(0xe00a) |
300 | #define MT9M114_PATCHLDR_PATCH_ID_1 CCI_REG16(0xe00c) |
301 | #define MT9M114_PATCHLDR_PATCH_ID_2 CCI_REG16(0xe00e) |
302 | #define MT9M114_PATCHLDR_PATCH_ID_3 CCI_REG16(0xe010) |
303 | #define MT9M114_PATCHLDR_PATCH_ID_4 CCI_REG16(0xe012) |
304 | #define MT9M114_PATCHLDR_PATCH_ID_5 CCI_REG16(0xe014) |
305 | #define MT9M114_PATCHLDR_PATCH_ID_6 CCI_REG16(0xe016) |
306 | #define MT9M114_PATCHLDR_PATCH_ID_7 CCI_REG16(0xe018) |
307 | |
308 | /* SYS_STATE values (for SYSMGR_NEXT_STATE and SYSMGR_CURRENT_STATE) */ |
309 | #define MT9M114_SYS_STATE_ENTER_CONFIG_CHANGE 0x28 |
310 | #define MT9M114_SYS_STATE_STREAMING 0x31 |
311 | #define MT9M114_SYS_STATE_START_STREAMING 0x34 |
312 | #define MT9M114_SYS_STATE_ENTER_SUSPEND 0x40 |
313 | #define MT9M114_SYS_STATE_SUSPENDED 0x41 |
314 | #define MT9M114_SYS_STATE_ENTER_STANDBY 0x50 |
315 | #define MT9M114_SYS_STATE_STANDBY 0x52 |
316 | #define MT9M114_SYS_STATE_LEAVE_STANDBY 0x54 |
317 | |
318 | /* Result status of last SET_STATE comamnd */ |
319 | #define MT9M114_SET_STATE_RESULT_ENOERR 0x00 |
320 | #define MT9M114_SET_STATE_RESULT_EINVAL 0x0c |
321 | #define MT9M114_SET_STATE_RESULT_ENOSPC 0x0d |
322 | |
323 | /* |
324 | * The minimum amount of horizontal and vertical blanking is undocumented. The |
325 | * minimum values that have been seen in register lists are 303 and 38, use |
326 | * them. |
327 | * |
328 | * Set the default to achieve 1280x960 at 30fps. |
329 | */ |
330 | #define MT9M114_MIN_HBLANK 303 |
331 | #define MT9M114_MIN_VBLANK 38 |
332 | #define MT9M114_DEF_HBLANK 323 |
333 | #define MT9M114_DEF_VBLANK 39 |
334 | |
335 | #define MT9M114_DEF_FRAME_RATE 30 |
336 | #define MT9M114_MAX_FRAME_RATE 120 |
337 | |
338 | #define MT9M114_PIXEL_ARRAY_WIDTH 1296U |
339 | #define MT9M114_PIXEL_ARRAY_HEIGHT 976U |
340 | |
341 | /* |
342 | * These values are not well documented and are semi-arbitrary. The pixel array |
343 | * minimum output size is 8 pixels larger than the minimum scaler cropped input |
344 | * width to account for the demosaicing. |
345 | */ |
346 | #define MT9M114_PIXEL_ARRAY_MIN_OUTPUT_WIDTH (32U + 8U) |
347 | #define MT9M114_PIXEL_ARRAY_MIN_OUTPUT_HEIGHT (32U + 8U) |
348 | #define MT9M114_SCALER_CROPPED_INPUT_WIDTH 32U |
349 | #define MT9M114_SCALER_CROPPED_INPUT_HEIGHT 32U |
350 | |
351 | /* Indices into the mt9m114.ifp.tpg array. */ |
352 | #define MT9M114_TPG_PATTERN 0 |
353 | #define MT9M114_TPG_RED 1 |
354 | #define MT9M114_TPG_GREEN 2 |
355 | #define MT9M114_TPG_BLUE 3 |
356 | |
357 | /* ----------------------------------------------------------------------------- |
358 | * Data Structures |
359 | */ |
360 | |
361 | enum mt9m114_format_flag { |
362 | MT9M114_FMT_FLAG_PARALLEL = BIT(0), |
363 | MT9M114_FMT_FLAG_CSI2 = BIT(1), |
364 | }; |
365 | |
366 | struct mt9m114_format_info { |
367 | u32 code; |
368 | u32 output_format; |
369 | u32 flags; |
370 | }; |
371 | |
372 | struct mt9m114 { |
373 | struct i2c_client *client; |
374 | struct regmap *regmap; |
375 | |
376 | struct clk *clk; |
377 | struct gpio_desc *reset; |
378 | struct regulator_bulk_data supplies[3]; |
379 | struct v4l2_fwnode_endpoint bus_cfg; |
380 | |
381 | struct { |
382 | unsigned int m; |
383 | unsigned int n; |
384 | unsigned int p; |
385 | } pll; |
386 | |
387 | unsigned int pixrate; |
388 | bool streaming; |
389 | |
390 | /* Pixel Array */ |
391 | struct { |
392 | struct v4l2_subdev sd; |
393 | struct media_pad pad; |
394 | |
395 | struct v4l2_ctrl_handler hdl; |
396 | struct v4l2_ctrl *exposure; |
397 | struct v4l2_ctrl *gain; |
398 | struct v4l2_ctrl *hblank; |
399 | struct v4l2_ctrl *vblank; |
400 | } pa; |
401 | |
402 | /* Image Flow Processor */ |
403 | struct { |
404 | struct v4l2_subdev sd; |
405 | struct media_pad pads[2]; |
406 | |
407 | struct v4l2_ctrl_handler hdl; |
408 | unsigned int frame_rate; |
409 | |
410 | struct v4l2_ctrl *tpg[4]; |
411 | } ifp; |
412 | }; |
413 | |
414 | /* ----------------------------------------------------------------------------- |
415 | * Formats |
416 | */ |
417 | |
418 | static const struct mt9m114_format_info mt9m114_format_infos[] = { |
419 | { |
420 | /* |
421 | * The first two entries are used as defaults, for parallel and |
422 | * CSI-2 buses respectively. Keep them in that order. |
423 | */ |
424 | .code = MEDIA_BUS_FMT_UYVY8_2X8, |
425 | .flags = MT9M114_FMT_FLAG_PARALLEL, |
426 | .output_format = MT9M114_CAM_OUTPUT_FORMAT_FORMAT_YUV, |
427 | }, { |
428 | .code = MEDIA_BUS_FMT_UYVY8_1X16, |
429 | .flags = MT9M114_FMT_FLAG_CSI2, |
430 | .output_format = MT9M114_CAM_OUTPUT_FORMAT_FORMAT_YUV, |
431 | }, { |
432 | .code = MEDIA_BUS_FMT_YUYV8_2X8, |
433 | .flags = MT9M114_FMT_FLAG_PARALLEL, |
434 | .output_format = MT9M114_CAM_OUTPUT_FORMAT_FORMAT_YUV |
435 | | MT9M114_CAM_OUTPUT_FORMAT_SWAP_BYTES, |
436 | }, { |
437 | .code = MEDIA_BUS_FMT_YUYV8_1X16, |
438 | .flags = MT9M114_FMT_FLAG_CSI2, |
439 | .output_format = MT9M114_CAM_OUTPUT_FORMAT_FORMAT_YUV |
440 | | MT9M114_CAM_OUTPUT_FORMAT_SWAP_BYTES, |
441 | }, { |
442 | .code = MEDIA_BUS_FMT_RGB565_2X8_LE, |
443 | .flags = MT9M114_FMT_FLAG_PARALLEL, |
444 | .output_format = MT9M114_CAM_OUTPUT_FORMAT_RGB_FORMAT_565RGB |
445 | | MT9M114_CAM_OUTPUT_FORMAT_FORMAT_RGB |
446 | | MT9M114_CAM_OUTPUT_FORMAT_SWAP_BYTES, |
447 | }, { |
448 | .code = MEDIA_BUS_FMT_RGB565_2X8_BE, |
449 | .flags = MT9M114_FMT_FLAG_PARALLEL, |
450 | .output_format = MT9M114_CAM_OUTPUT_FORMAT_RGB_FORMAT_565RGB |
451 | | MT9M114_CAM_OUTPUT_FORMAT_FORMAT_RGB, |
452 | }, { |
453 | .code = MEDIA_BUS_FMT_RGB565_1X16, |
454 | .flags = MT9M114_FMT_FLAG_CSI2, |
455 | .output_format = MT9M114_CAM_OUTPUT_FORMAT_RGB_FORMAT_565RGB |
456 | | MT9M114_CAM_OUTPUT_FORMAT_FORMAT_RGB, |
457 | }, { |
458 | .code = MEDIA_BUS_FMT_SGRBG8_1X8, |
459 | .output_format = MT9M114_CAM_OUTPUT_FORMAT_BAYER_FORMAT_PROCESSED8 |
460 | | MT9M114_CAM_OUTPUT_FORMAT_FORMAT_BAYER, |
461 | .flags = MT9M114_FMT_FLAG_PARALLEL | MT9M114_FMT_FLAG_CSI2, |
462 | }, { |
463 | /* Keep the format compatible with the IFP sink pad last. */ |
464 | .code = MEDIA_BUS_FMT_SGRBG10_1X10, |
465 | .output_format = MT9M114_CAM_OUTPUT_FORMAT_BAYER_FORMAT_RAWR10 |
466 | | MT9M114_CAM_OUTPUT_FORMAT_FORMAT_BAYER, |
467 | .flags = MT9M114_FMT_FLAG_PARALLEL | MT9M114_FMT_FLAG_CSI2, |
468 | } |
469 | }; |
470 | |
471 | static const struct mt9m114_format_info * |
472 | mt9m114_default_format_info(struct mt9m114 *sensor) |
473 | { |
474 | if (sensor->bus_cfg.bus_type == V4L2_MBUS_CSI2_DPHY) |
475 | return &mt9m114_format_infos[1]; |
476 | else |
477 | return &mt9m114_format_infos[0]; |
478 | } |
479 | |
480 | static const struct mt9m114_format_info * |
481 | mt9m114_format_info(struct mt9m114 *sensor, unsigned int pad, u32 code) |
482 | { |
483 | const unsigned int num_formats = ARRAY_SIZE(mt9m114_format_infos); |
484 | unsigned int flag; |
485 | unsigned int i; |
486 | |
487 | switch (pad) { |
488 | case 0: |
489 | return &mt9m114_format_infos[num_formats - 1]; |
490 | |
491 | case 1: |
492 | if (sensor->bus_cfg.bus_type == V4L2_MBUS_CSI2_DPHY) |
493 | flag = MT9M114_FMT_FLAG_CSI2; |
494 | else |
495 | flag = MT9M114_FMT_FLAG_PARALLEL; |
496 | |
497 | for (i = 0; i < num_formats; ++i) { |
498 | const struct mt9m114_format_info *info = |
499 | &mt9m114_format_infos[i]; |
500 | |
501 | if (info->code == code && info->flags & flag) |
502 | return info; |
503 | } |
504 | |
505 | return mt9m114_default_format_info(sensor); |
506 | |
507 | default: |
508 | return NULL; |
509 | } |
510 | } |
511 | |
512 | /* ----------------------------------------------------------------------------- |
513 | * Initialization |
514 | */ |
515 | |
516 | static const struct cci_reg_sequence mt9m114_init[] = { |
517 | { MT9M114_RESET_REGISTER, MT9M114_RESET_REGISTER_MASK_BAD | |
518 | MT9M114_RESET_REGISTER_LOCK_REG | |
519 | 0x0010 }, |
520 | |
521 | /* Sensor optimization */ |
522 | { CCI_REG16(0x316a), 0x8270 }, |
523 | { CCI_REG16(0x316c), 0x8270 }, |
524 | { CCI_REG16(0x3ed0), 0x2305 }, |
525 | { CCI_REG16(0x3ed2), 0x77cf }, |
526 | { CCI_REG16(0x316e), 0x8202 }, |
527 | { CCI_REG16(0x3180), 0x87ff }, |
528 | { CCI_REG16(0x30d4), 0x6080 }, |
529 | { CCI_REG16(0xa802), 0x0008 }, |
530 | |
531 | { CCI_REG16(0x3e14), 0xff39 }, |
532 | |
533 | /* APGA */ |
534 | { MT9M114_CAM_PGA_PGA_CONTROL, 0x0000 }, |
535 | |
536 | /* Automatic White balance */ |
537 | { MT9M114_CAM_AWB_CCM_L(0), 0x0267 }, |
538 | { MT9M114_CAM_AWB_CCM_L(1), 0xff1a }, |
539 | { MT9M114_CAM_AWB_CCM_L(2), 0xffb3 }, |
540 | { MT9M114_CAM_AWB_CCM_L(3), 0xff80 }, |
541 | { MT9M114_CAM_AWB_CCM_L(4), 0x0166 }, |
542 | { MT9M114_CAM_AWB_CCM_L(5), 0x0003 }, |
543 | { MT9M114_CAM_AWB_CCM_L(6), 0xff9a }, |
544 | { MT9M114_CAM_AWB_CCM_L(7), 0xfeb4 }, |
545 | { MT9M114_CAM_AWB_CCM_L(8), 0x024d }, |
546 | { MT9M114_CAM_AWB_CCM_M(0), 0x01bf }, |
547 | { MT9M114_CAM_AWB_CCM_M(1), 0xff01 }, |
548 | { MT9M114_CAM_AWB_CCM_M(2), 0xfff3 }, |
549 | { MT9M114_CAM_AWB_CCM_M(3), 0xff75 }, |
550 | { MT9M114_CAM_AWB_CCM_M(4), 0x0198 }, |
551 | { MT9M114_CAM_AWB_CCM_M(5), 0xfffd }, |
552 | { MT9M114_CAM_AWB_CCM_M(6), 0xff9a }, |
553 | { MT9M114_CAM_AWB_CCM_M(7), 0xfee7 }, |
554 | { MT9M114_CAM_AWB_CCM_M(8), 0x02a8 }, |
555 | { MT9M114_CAM_AWB_CCM_R(0), 0x01d9 }, |
556 | { MT9M114_CAM_AWB_CCM_R(1), 0xff26 }, |
557 | { MT9M114_CAM_AWB_CCM_R(2), 0xfff3 }, |
558 | { MT9M114_CAM_AWB_CCM_R(3), 0xffb3 }, |
559 | { MT9M114_CAM_AWB_CCM_R(4), 0x0132 }, |
560 | { MT9M114_CAM_AWB_CCM_R(5), 0xffe8 }, |
561 | { MT9M114_CAM_AWB_CCM_R(6), 0xffda }, |
562 | { MT9M114_CAM_AWB_CCM_R(7), 0xfecd }, |
563 | { MT9M114_CAM_AWB_CCM_R(8), 0x02c2 }, |
564 | { MT9M114_CAM_AWB_CCM_L_RG_GAIN, 0x0075 }, |
565 | { MT9M114_CAM_AWB_CCM_L_BG_GAIN, 0x011c }, |
566 | { MT9M114_CAM_AWB_CCM_M_RG_GAIN, 0x009a }, |
567 | { MT9M114_CAM_AWB_CCM_M_BG_GAIN, 0x0105 }, |
568 | { MT9M114_CAM_AWB_CCM_R_RG_GAIN, 0x00a4 }, |
569 | { MT9M114_CAM_AWB_CCM_R_BG_GAIN, 0x00ac }, |
570 | { MT9M114_CAM_AWB_CCM_L_CTEMP, 0x0a8c }, |
571 | { MT9M114_CAM_AWB_CCM_M_CTEMP, 0x0f0a }, |
572 | { MT9M114_CAM_AWB_CCM_R_CTEMP, 0x1964 }, |
573 | { MT9M114_CAM_AWB_AWB_XSHIFT_PRE_ADJ, 51 }, |
574 | { MT9M114_CAM_AWB_AWB_YSHIFT_PRE_ADJ, 60 }, |
575 | { MT9M114_CAM_AWB_AWB_XSCALE, 3 }, |
576 | { MT9M114_CAM_AWB_AWB_YSCALE, 2 }, |
577 | { MT9M114_CAM_AWB_AWB_WEIGHTS(0), 0x0000 }, |
578 | { MT9M114_CAM_AWB_AWB_WEIGHTS(1), 0x0000 }, |
579 | { MT9M114_CAM_AWB_AWB_WEIGHTS(2), 0x0000 }, |
580 | { MT9M114_CAM_AWB_AWB_WEIGHTS(3), 0xe724 }, |
581 | { MT9M114_CAM_AWB_AWB_WEIGHTS(4), 0x1583 }, |
582 | { MT9M114_CAM_AWB_AWB_WEIGHTS(5), 0x2045 }, |
583 | { MT9M114_CAM_AWB_AWB_WEIGHTS(6), 0x03ff }, |
584 | { MT9M114_CAM_AWB_AWB_WEIGHTS(7), 0x007c }, |
585 | { MT9M114_CAM_AWB_K_R_L, 0x80 }, |
586 | { MT9M114_CAM_AWB_K_G_L, 0x80 }, |
587 | { MT9M114_CAM_AWB_K_B_L, 0x80 }, |
588 | { MT9M114_CAM_AWB_K_R_R, 0x88 }, |
589 | { MT9M114_CAM_AWB_K_G_R, 0x80 }, |
590 | { MT9M114_CAM_AWB_K_B_R, 0x80 }, |
591 | |
592 | /* Low-Light Image Enhancements */ |
593 | { MT9M114_CAM_LL_START_BRIGHTNESS, 0x0020 }, |
594 | { MT9M114_CAM_LL_STOP_BRIGHTNESS, 0x009a }, |
595 | { MT9M114_CAM_LL_START_GAIN_METRIC, 0x0070 }, |
596 | { MT9M114_CAM_LL_STOP_GAIN_METRIC, 0x00f3 }, |
597 | { MT9M114_CAM_LL_START_CONTRAST_LUMA_PERCENTAGE, 0x20 }, |
598 | { MT9M114_CAM_LL_STOP_CONTRAST_LUMA_PERCENTAGE, 0x9a }, |
599 | { MT9M114_CAM_LL_START_SATURATION, 0x80 }, |
600 | { MT9M114_CAM_LL_END_SATURATION, 0x4b }, |
601 | { MT9M114_CAM_LL_START_DESATURATION, 0x00 }, |
602 | { MT9M114_CAM_LL_END_DESATURATION, 0xff }, |
603 | { MT9M114_CAM_LL_START_DEMOSAICING, 0x3c }, |
604 | { MT9M114_CAM_LL_START_AP_GAIN, 0x02 }, |
605 | { MT9M114_CAM_LL_START_AP_THRESH, 0x06 }, |
606 | { MT9M114_CAM_LL_STOP_DEMOSAICING, 0x64 }, |
607 | { MT9M114_CAM_LL_STOP_AP_GAIN, 0x01 }, |
608 | { MT9M114_CAM_LL_STOP_AP_THRESH, 0x0c }, |
609 | { MT9M114_CAM_LL_START_NR_RED, 0x3c }, |
610 | { MT9M114_CAM_LL_START_NR_GREEN, 0x3c }, |
611 | { MT9M114_CAM_LL_START_NR_BLUE, 0x3c }, |
612 | { MT9M114_CAM_LL_START_NR_THRESH, 0x0f }, |
613 | { MT9M114_CAM_LL_STOP_NR_RED, 0x64 }, |
614 | { MT9M114_CAM_LL_STOP_NR_GREEN, 0x64 }, |
615 | { MT9M114_CAM_LL_STOP_NR_BLUE, 0x64 }, |
616 | { MT9M114_CAM_LL_STOP_NR_THRESH, 0x32 }, |
617 | { MT9M114_CAM_LL_START_CONTRAST_BM, 0x0020 }, |
618 | { MT9M114_CAM_LL_STOP_CONTRAST_BM, 0x009a }, |
619 | { MT9M114_CAM_LL_GAMMA, 0x00dc }, |
620 | { MT9M114_CAM_LL_START_CONTRAST_GRADIENT, 0x38 }, |
621 | { MT9M114_CAM_LL_STOP_CONTRAST_GRADIENT, 0x30 }, |
622 | { MT9M114_CAM_LL_START_CONTRAST_LUMA_PERCENTAGE, 0x50 }, |
623 | { MT9M114_CAM_LL_STOP_CONTRAST_LUMA_PERCENTAGE, 0x19 }, |
624 | { MT9M114_CAM_LL_START_FADE_TO_BLACK_LUMA, 0x0230 }, |
625 | { MT9M114_CAM_LL_STOP_FADE_TO_BLACK_LUMA, 0x0010 }, |
626 | { MT9M114_CAM_LL_CLUSTER_DC_TH_BM, 0x01cd }, |
627 | { MT9M114_CAM_LL_CLUSTER_DC_GATE_PERCENTAGE, 0x05 }, |
628 | { MT9M114_CAM_LL_SUMMING_SENSITIVITY_FACTOR, 0x40 }, |
629 | |
630 | /* Auto-Exposure */ |
631 | { MT9M114_CAM_AET_TARGET_AVERAGE_LUMA_DARK, 0x1b }, |
632 | { MT9M114_CAM_AET_AEMODE, 0x00 }, |
633 | { MT9M114_CAM_AET_TARGET_GAIN, 0x0080 }, |
634 | { MT9M114_CAM_AET_AE_MAX_VIRT_AGAIN, 0x0100 }, |
635 | { MT9M114_CAM_AET_BLACK_CLIPPING_TARGET, 0x005a }, |
636 | |
637 | { MT9M114_CCM_DELTA_GAIN, 0x05 }, |
638 | { MT9M114_AE_TRACK_AE_TRACKING_DAMPENING_SPEED, 0x20 }, |
639 | |
640 | /* Pixel array timings and integration time */ |
641 | { MT9M114_CAM_SENSOR_CFG_ROW_SPEED, 1 }, |
642 | { MT9M114_CAM_SENSOR_CFG_FINE_INTEG_TIME_MIN, 219 }, |
643 | { MT9M114_CAM_SENSOR_CFG_FINE_INTEG_TIME_MAX, 1459 }, |
644 | { MT9M114_CAM_SENSOR_CFG_FINE_CORRECTION, 96 }, |
645 | { MT9M114_CAM_SENSOR_CFG_REG_0_DATA, 32 }, |
646 | |
647 | /* Miscellaneous settings */ |
648 | { MT9M114_PAD_SLEW, 0x0777 }, |
649 | }; |
650 | |
651 | /* ----------------------------------------------------------------------------- |
652 | * Hardware Configuration |
653 | */ |
654 | |
655 | /* Wait for a command to complete. */ |
656 | static int mt9m114_poll_command(struct mt9m114 *sensor, u32 command) |
657 | { |
658 | unsigned int i; |
659 | u64 value; |
660 | int ret; |
661 | |
662 | for (i = 0; i < 100; ++i) { |
663 | ret = cci_read(map: sensor->regmap, MT9M114_COMMAND_REGISTER, val: &value, |
664 | NULL); |
665 | if (ret < 0) |
666 | return ret; |
667 | |
668 | if (!(value & command)) |
669 | break; |
670 | |
671 | usleep_range(min: 5000, max: 6000); |
672 | } |
673 | |
674 | if (value & command) { |
675 | dev_err(&sensor->client->dev, "Command %u completion timeout\n", |
676 | command); |
677 | return -ETIMEDOUT; |
678 | } |
679 | |
680 | if (!(value & MT9M114_COMMAND_REGISTER_OK)) { |
681 | dev_err(&sensor->client->dev, "Command %u failed\n", command); |
682 | return -EIO; |
683 | } |
684 | |
685 | return 0; |
686 | } |
687 | |
688 | /* Wait for a state to be entered. */ |
689 | static int mt9m114_poll_state(struct mt9m114 *sensor, u32 state) |
690 | { |
691 | unsigned int i; |
692 | u64 value; |
693 | int ret; |
694 | |
695 | for (i = 0; i < 100; ++i) { |
696 | ret = cci_read(map: sensor->regmap, MT9M114_SYSMGR_CURRENT_STATE, |
697 | val: &value, NULL); |
698 | if (ret < 0) |
699 | return ret; |
700 | |
701 | if (value == state) |
702 | return 0; |
703 | |
704 | usleep_range(min: 1000, max: 1500); |
705 | } |
706 | |
707 | dev_err(&sensor->client->dev, "Timeout waiting for state 0x%02x\n", |
708 | state); |
709 | return -ETIMEDOUT; |
710 | } |
711 | |
712 | static int mt9m114_set_state(struct mt9m114 *sensor, u8 next_state) |
713 | { |
714 | int ret = 0; |
715 | |
716 | /* Set the next desired state and start the state transition. */ |
717 | cci_write(map: sensor->regmap, MT9M114_SYSMGR_NEXT_STATE, val: next_state, err: &ret); |
718 | cci_write(map: sensor->regmap, MT9M114_COMMAND_REGISTER, |
719 | MT9M114_COMMAND_REGISTER_OK | |
720 | MT9M114_COMMAND_REGISTER_SET_STATE, err: &ret); |
721 | if (ret < 0) |
722 | return ret; |
723 | |
724 | /* Wait for the state transition to complete. */ |
725 | ret = mt9m114_poll_command(sensor, MT9M114_COMMAND_REGISTER_SET_STATE); |
726 | if (ret < 0) |
727 | return ret; |
728 | |
729 | return 0; |
730 | } |
731 | |
732 | static int mt9m114_initialize(struct mt9m114 *sensor) |
733 | { |
734 | u32 value; |
735 | int ret; |
736 | |
737 | ret = cci_multi_reg_write(map: sensor->regmap, regs: mt9m114_init, |
738 | ARRAY_SIZE(mt9m114_init), NULL); |
739 | if (ret < 0) { |
740 | dev_err(&sensor->client->dev, |
741 | "Failed to initialize the sensor\n"); |
742 | return ret; |
743 | } |
744 | |
745 | /* Configure the PLL. */ |
746 | cci_write(map: sensor->regmap, MT9M114_CAM_SYSCTL_PLL_ENABLE, |
747 | MT9M114_CAM_SYSCTL_PLL_ENABLE_VALUE, err: &ret); |
748 | cci_write(map: sensor->regmap, MT9M114_CAM_SYSCTL_PLL_DIVIDER_M_N, |
749 | MT9M114_CAM_SYSCTL_PLL_DIVIDER_VALUE(sensor->pll.m, |
750 | sensor->pll.n), |
751 | err: &ret); |
752 | cci_write(map: sensor->regmap, MT9M114_CAM_SYSCTL_PLL_DIVIDER_P, |
753 | MT9M114_CAM_SYSCTL_PLL_DIVIDER_P_VALUE(sensor->pll.p), err: &ret); |
754 | cci_write(map: sensor->regmap, MT9M114_CAM_SENSOR_CFG_PIXCLK, |
755 | val: sensor->pixrate, err: &ret); |
756 | |
757 | /* Configure the output mode. */ |
758 | if (sensor->bus_cfg.bus_type == V4L2_MBUS_CSI2_DPHY) { |
759 | value = MT9M114_CAM_PORT_PORT_SELECT_MIPI |
760 | | MT9M114_CAM_PORT_CHAN_NUM(0) |
761 | | 0x8000; |
762 | if (!(sensor->bus_cfg.bus.mipi_csi2.flags & |
763 | V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK)) |
764 | value |= MT9M114_CAM_PORT_CONT_MIPI_CLK; |
765 | } else { |
766 | value = MT9M114_CAM_PORT_PORT_SELECT_PARALLEL |
767 | | 0x8000; |
768 | } |
769 | cci_write(map: sensor->regmap, MT9M114_CAM_PORT_OUTPUT_CONTROL, val: value, err: &ret); |
770 | if (ret < 0) |
771 | return ret; |
772 | |
773 | ret = mt9m114_set_state(sensor, MT9M114_SYS_STATE_ENTER_CONFIG_CHANGE); |
774 | if (ret < 0) |
775 | return ret; |
776 | |
777 | ret = mt9m114_set_state(sensor, MT9M114_SYS_STATE_ENTER_SUSPEND); |
778 | if (ret < 0) |
779 | return ret; |
780 | |
781 | return 0; |
782 | } |
783 | |
784 | static int mt9m114_configure(struct mt9m114 *sensor, |
785 | struct v4l2_subdev_state *pa_state, |
786 | struct v4l2_subdev_state *ifp_state) |
787 | { |
788 | const struct v4l2_mbus_framefmt *pa_format; |
789 | const struct v4l2_rect *pa_crop; |
790 | const struct mt9m114_format_info *ifp_info; |
791 | const struct v4l2_mbus_framefmt *ifp_format; |
792 | const struct v4l2_rect *ifp_crop; |
793 | const struct v4l2_rect *ifp_compose; |
794 | unsigned int hratio, vratio; |
795 | u64 output_format; |
796 | u64 read_mode; |
797 | int ret = 0; |
798 | |
799 | pa_format = v4l2_subdev_state_get_format(pa_state, 0); |
800 | pa_crop = v4l2_subdev_state_get_crop(pa_state, 0); |
801 | |
802 | ifp_format = v4l2_subdev_state_get_format(ifp_state, 1); |
803 | ifp_info = mt9m114_format_info(sensor, pad: 1, code: ifp_format->code); |
804 | ifp_crop = v4l2_subdev_state_get_crop(ifp_state, 0); |
805 | ifp_compose = v4l2_subdev_state_get_compose(ifp_state, 0); |
806 | |
807 | ret = cci_read(map: sensor->regmap, MT9M114_CAM_SENSOR_CONTROL_READ_MODE, |
808 | val: &read_mode, NULL); |
809 | if (ret < 0) |
810 | return ret; |
811 | |
812 | ret = cci_read(map: sensor->regmap, MT9M114_CAM_OUTPUT_FORMAT, |
813 | val: &output_format, NULL); |
814 | if (ret < 0) |
815 | return ret; |
816 | |
817 | hratio = pa_crop->width / pa_format->width; |
818 | vratio = pa_crop->height / pa_format->height; |
819 | |
820 | /* |
821 | * Pixel array crop and binning. The CAM_SENSOR_CFG_CPIPE_LAST_ROW |
822 | * register isn't clearly documented, but is always set to the number |
823 | * of active rows minus 4 divided by the vertical binning factor in all |
824 | * example sensor modes. |
825 | */ |
826 | cci_write(map: sensor->regmap, MT9M114_CAM_SENSOR_CFG_X_ADDR_START, |
827 | val: pa_crop->left, err: &ret); |
828 | cci_write(map: sensor->regmap, MT9M114_CAM_SENSOR_CFG_Y_ADDR_START, |
829 | val: pa_crop->top, err: &ret); |
830 | cci_write(map: sensor->regmap, MT9M114_CAM_SENSOR_CFG_X_ADDR_END, |
831 | val: pa_crop->width + pa_crop->left - 1, err: &ret); |
832 | cci_write(map: sensor->regmap, MT9M114_CAM_SENSOR_CFG_Y_ADDR_END, |
833 | val: pa_crop->height + pa_crop->top - 1, err: &ret); |
834 | cci_write(map: sensor->regmap, MT9M114_CAM_SENSOR_CFG_CPIPE_LAST_ROW, |
835 | val: (pa_crop->height - 4) / vratio - 1, err: &ret); |
836 | |
837 | read_mode &= ~(MT9M114_CAM_SENSOR_CONTROL_X_READ_OUT_MASK | |
838 | MT9M114_CAM_SENSOR_CONTROL_Y_READ_OUT_MASK); |
839 | |
840 | if (hratio > 1) |
841 | read_mode |= MT9M114_CAM_SENSOR_CONTROL_X_READ_OUT_SUMMING; |
842 | if (vratio > 1) |
843 | read_mode |= MT9M114_CAM_SENSOR_CONTROL_Y_READ_OUT_SUMMING; |
844 | |
845 | cci_write(map: sensor->regmap, MT9M114_CAM_SENSOR_CONTROL_READ_MODE, |
846 | val: read_mode, err: &ret); |
847 | |
848 | /* |
849 | * Color pipeline (IFP) cropping and scaling. Subtract 4 from the left |
850 | * and top coordinates to compensate for the lines and columns removed |
851 | * by demosaicing that are taken into account in the crop rectangle but |
852 | * not in the hardware. |
853 | */ |
854 | cci_write(map: sensor->regmap, MT9M114_CAM_CROP_WINDOW_XOFFSET, |
855 | val: ifp_crop->left - 4, err: &ret); |
856 | cci_write(map: sensor->regmap, MT9M114_CAM_CROP_WINDOW_YOFFSET, |
857 | val: ifp_crop->top - 4, err: &ret); |
858 | cci_write(map: sensor->regmap, MT9M114_CAM_CROP_WINDOW_WIDTH, |
859 | val: ifp_crop->width, err: &ret); |
860 | cci_write(map: sensor->regmap, MT9M114_CAM_CROP_WINDOW_HEIGHT, |
861 | val: ifp_crop->height, err: &ret); |
862 | |
863 | cci_write(map: sensor->regmap, MT9M114_CAM_OUTPUT_WIDTH, |
864 | val: ifp_compose->width, err: &ret); |
865 | cci_write(map: sensor->regmap, MT9M114_CAM_OUTPUT_HEIGHT, |
866 | val: ifp_compose->height, err: &ret); |
867 | |
868 | /* AWB and AE windows, use the full frame. */ |
869 | cci_write(map: sensor->regmap, MT9M114_CAM_STAT_AWB_CLIP_WINDOW_XSTART, |
870 | val: 0, err: &ret); |
871 | cci_write(map: sensor->regmap, MT9M114_CAM_STAT_AWB_CLIP_WINDOW_YSTART, |
872 | val: 0, err: &ret); |
873 | cci_write(map: sensor->regmap, MT9M114_CAM_STAT_AWB_CLIP_WINDOW_XEND, |
874 | val: ifp_compose->width - 1, err: &ret); |
875 | cci_write(map: sensor->regmap, MT9M114_CAM_STAT_AWB_CLIP_WINDOW_YEND, |
876 | val: ifp_compose->height - 1, err: &ret); |
877 | |
878 | cci_write(map: sensor->regmap, MT9M114_CAM_STAT_AE_INITIAL_WINDOW_XSTART, |
879 | val: 0, err: &ret); |
880 | cci_write(map: sensor->regmap, MT9M114_CAM_STAT_AE_INITIAL_WINDOW_YSTART, |
881 | val: 0, err: &ret); |
882 | cci_write(map: sensor->regmap, MT9M114_CAM_STAT_AE_INITIAL_WINDOW_XEND, |
883 | val: ifp_compose->width / 5 - 1, err: &ret); |
884 | cci_write(map: sensor->regmap, MT9M114_CAM_STAT_AE_INITIAL_WINDOW_YEND, |
885 | val: ifp_compose->height / 5 - 1, err: &ret); |
886 | |
887 | cci_write(map: sensor->regmap, MT9M114_CAM_CROP_CROPMODE, |
888 | MT9M114_CAM_CROP_MODE_AWB_AUTO_CROP_EN | |
889 | MT9M114_CAM_CROP_MODE_AE_AUTO_CROP_EN, err: &ret); |
890 | |
891 | /* Set the media bus code. */ |
892 | output_format &= ~(MT9M114_CAM_OUTPUT_FORMAT_RGB_FORMAT_MASK | |
893 | MT9M114_CAM_OUTPUT_FORMAT_BAYER_FORMAT_MASK | |
894 | MT9M114_CAM_OUTPUT_FORMAT_FORMAT_MASK | |
895 | MT9M114_CAM_OUTPUT_FORMAT_SWAP_BYTES | |
896 | MT9M114_CAM_OUTPUT_FORMAT_SWAP_RED_BLUE); |
897 | output_format |= ifp_info->output_format; |
898 | |
899 | cci_write(map: sensor->regmap, MT9M114_CAM_OUTPUT_FORMAT, |
900 | val: output_format, err: &ret); |
901 | |
902 | return ret; |
903 | } |
904 | |
905 | static int mt9m114_set_frame_rate(struct mt9m114 *sensor) |
906 | { |
907 | u16 frame_rate = sensor->ifp.frame_rate << 8; |
908 | int ret = 0; |
909 | |
910 | cci_write(map: sensor->regmap, MT9M114_CAM_AET_MIN_FRAME_RATE, |
911 | val: frame_rate, err: &ret); |
912 | cci_write(map: sensor->regmap, MT9M114_CAM_AET_MAX_FRAME_RATE, |
913 | val: frame_rate, err: &ret); |
914 | |
915 | return ret; |
916 | } |
917 | |
918 | static int mt9m114_start_streaming(struct mt9m114 *sensor, |
919 | struct v4l2_subdev_state *pa_state, |
920 | struct v4l2_subdev_state *ifp_state) |
921 | { |
922 | int ret; |
923 | |
924 | ret = pm_runtime_resume_and_get(dev: &sensor->client->dev); |
925 | if (ret) |
926 | return ret; |
927 | |
928 | ret = mt9m114_configure(sensor, pa_state, ifp_state); |
929 | if (ret) |
930 | goto error; |
931 | |
932 | ret = mt9m114_set_frame_rate(sensor); |
933 | if (ret) |
934 | goto error; |
935 | |
936 | ret = __v4l2_ctrl_handler_setup(hdl: &sensor->pa.hdl); |
937 | if (ret) |
938 | goto error; |
939 | |
940 | ret = __v4l2_ctrl_handler_setup(hdl: &sensor->ifp.hdl); |
941 | if (ret) |
942 | goto error; |
943 | |
944 | /* |
945 | * The Change-Config state is transient and moves to the streaming |
946 | * state automatically. |
947 | */ |
948 | ret = mt9m114_set_state(sensor, MT9M114_SYS_STATE_ENTER_CONFIG_CHANGE); |
949 | if (ret) |
950 | goto error; |
951 | |
952 | sensor->streaming = true; |
953 | |
954 | return 0; |
955 | |
956 | error: |
957 | pm_runtime_mark_last_busy(dev: &sensor->client->dev); |
958 | pm_runtime_put_autosuspend(dev: &sensor->client->dev); |
959 | |
960 | return ret; |
961 | } |
962 | |
963 | static int mt9m114_stop_streaming(struct mt9m114 *sensor) |
964 | { |
965 | int ret; |
966 | |
967 | sensor->streaming = false; |
968 | |
969 | ret = mt9m114_set_state(sensor, MT9M114_SYS_STATE_ENTER_SUSPEND); |
970 | |
971 | pm_runtime_mark_last_busy(dev: &sensor->client->dev); |
972 | pm_runtime_put_autosuspend(dev: &sensor->client->dev); |
973 | |
974 | return ret; |
975 | } |
976 | |
977 | /* ----------------------------------------------------------------------------- |
978 | * Common Subdev Operations |
979 | */ |
980 | |
981 | static const struct media_entity_operations mt9m114_entity_ops = { |
982 | .link_validate = v4l2_subdev_link_validate, |
983 | }; |
984 | |
985 | /* ----------------------------------------------------------------------------- |
986 | * Pixel Array Control Operations |
987 | */ |
988 | |
989 | static inline struct mt9m114 *pa_ctrl_to_mt9m114(struct v4l2_ctrl *ctrl) |
990 | { |
991 | return container_of(ctrl->handler, struct mt9m114, pa.hdl); |
992 | } |
993 | |
994 | static int mt9m114_pa_g_ctrl(struct v4l2_ctrl *ctrl) |
995 | { |
996 | struct mt9m114 *sensor = pa_ctrl_to_mt9m114(ctrl); |
997 | u64 value; |
998 | int ret; |
999 | |
1000 | if (!pm_runtime_get_if_in_use(dev: &sensor->client->dev)) |
1001 | return 0; |
1002 | |
1003 | switch (ctrl->id) { |
1004 | case V4L2_CID_EXPOSURE: |
1005 | ret = cci_read(map: sensor->regmap, |
1006 | MT9M114_CAM_SENSOR_CONTROL_COARSE_INTEGRATION_TIME, |
1007 | val: &value, NULL); |
1008 | if (ret) |
1009 | break; |
1010 | |
1011 | ctrl->val = value; |
1012 | break; |
1013 | |
1014 | case V4L2_CID_ANALOGUE_GAIN: |
1015 | ret = cci_read(map: sensor->regmap, |
1016 | MT9M114_CAM_SENSOR_CONTROL_ANALOG_GAIN, |
1017 | val: &value, NULL); |
1018 | if (ret) |
1019 | break; |
1020 | |
1021 | ctrl->val = value; |
1022 | break; |
1023 | |
1024 | default: |
1025 | ret = -EINVAL; |
1026 | break; |
1027 | } |
1028 | |
1029 | pm_runtime_mark_last_busy(dev: &sensor->client->dev); |
1030 | pm_runtime_put_autosuspend(dev: &sensor->client->dev); |
1031 | |
1032 | return ret; |
1033 | } |
1034 | |
1035 | static int mt9m114_pa_s_ctrl(struct v4l2_ctrl *ctrl) |
1036 | { |
1037 | struct mt9m114 *sensor = pa_ctrl_to_mt9m114(ctrl); |
1038 | const struct v4l2_mbus_framefmt *format; |
1039 | struct v4l2_subdev_state *state; |
1040 | int ret = 0; |
1041 | u64 mask; |
1042 | |
1043 | /* V4L2 controls values are applied only when power is up. */ |
1044 | if (!pm_runtime_get_if_in_use(dev: &sensor->client->dev)) |
1045 | return 0; |
1046 | |
1047 | state = v4l2_subdev_get_locked_active_state(sd: &sensor->pa.sd); |
1048 | format = v4l2_subdev_state_get_format(state, 0); |
1049 | |
1050 | switch (ctrl->id) { |
1051 | case V4L2_CID_HBLANK: |
1052 | cci_write(map: sensor->regmap, MT9M114_CAM_SENSOR_CFG_LINE_LENGTH_PCK, |
1053 | val: ctrl->val + format->width, err: &ret); |
1054 | break; |
1055 | |
1056 | case V4L2_CID_VBLANK: |
1057 | cci_write(map: sensor->regmap, MT9M114_CAM_SENSOR_CFG_FRAME_LENGTH_LINES, |
1058 | val: ctrl->val + format->height, err: &ret); |
1059 | break; |
1060 | |
1061 | case V4L2_CID_EXPOSURE: |
1062 | cci_write(map: sensor->regmap, |
1063 | MT9M114_CAM_SENSOR_CONTROL_COARSE_INTEGRATION_TIME, |
1064 | val: ctrl->val, err: &ret); |
1065 | break; |
1066 | |
1067 | case V4L2_CID_ANALOGUE_GAIN: |
1068 | /* |
1069 | * The CAM_SENSOR_CONTROL_ANALOG_GAIN contains linear analog |
1070 | * gain values that are mapped to the GLOBAL_GAIN register |
1071 | * values by the sensor firmware. |
1072 | */ |
1073 | cci_write(map: sensor->regmap, MT9M114_CAM_SENSOR_CONTROL_ANALOG_GAIN, |
1074 | val: ctrl->val, err: &ret); |
1075 | break; |
1076 | |
1077 | case V4L2_CID_HFLIP: |
1078 | mask = MT9M114_CAM_SENSOR_CONTROL_HORZ_MIRROR_EN; |
1079 | ret = cci_update_bits(map: sensor->regmap, |
1080 | MT9M114_CAM_SENSOR_CONTROL_READ_MODE, |
1081 | mask, val: ctrl->val ? mask : 0, NULL); |
1082 | break; |
1083 | |
1084 | case V4L2_CID_VFLIP: |
1085 | mask = MT9M114_CAM_SENSOR_CONTROL_VERT_FLIP_EN; |
1086 | ret = cci_update_bits(map: sensor->regmap, |
1087 | MT9M114_CAM_SENSOR_CONTROL_READ_MODE, |
1088 | mask, val: ctrl->val ? mask : 0, NULL); |
1089 | break; |
1090 | |
1091 | default: |
1092 | ret = -EINVAL; |
1093 | break; |
1094 | } |
1095 | |
1096 | pm_runtime_mark_last_busy(dev: &sensor->client->dev); |
1097 | pm_runtime_put_autosuspend(dev: &sensor->client->dev); |
1098 | |
1099 | return ret; |
1100 | } |
1101 | |
1102 | static const struct v4l2_ctrl_ops mt9m114_pa_ctrl_ops = { |
1103 | .g_volatile_ctrl = mt9m114_pa_g_ctrl, |
1104 | .s_ctrl = mt9m114_pa_s_ctrl, |
1105 | }; |
1106 | |
1107 | static void mt9m114_pa_ctrl_update_exposure(struct mt9m114 *sensor, bool manual) |
1108 | { |
1109 | /* |
1110 | * Update the volatile flag on the manual exposure and gain controls. |
1111 | * If the controls have switched to manual, read their current value |
1112 | * from the hardware to ensure that control read and write operations |
1113 | * will behave correctly |
1114 | */ |
1115 | if (manual) { |
1116 | mt9m114_pa_g_ctrl(ctrl: sensor->pa.exposure); |
1117 | sensor->pa.exposure->cur.val = sensor->pa.exposure->val; |
1118 | sensor->pa.exposure->flags &= ~V4L2_CTRL_FLAG_VOLATILE; |
1119 | |
1120 | mt9m114_pa_g_ctrl(ctrl: sensor->pa.gain); |
1121 | sensor->pa.gain->cur.val = sensor->pa.gain->val; |
1122 | sensor->pa.gain->flags &= ~V4L2_CTRL_FLAG_VOLATILE; |
1123 | } else { |
1124 | sensor->pa.exposure->flags |= V4L2_CTRL_FLAG_VOLATILE; |
1125 | sensor->pa.gain->flags |= V4L2_CTRL_FLAG_VOLATILE; |
1126 | } |
1127 | } |
1128 | |
1129 | static void mt9m114_pa_ctrl_update_blanking(struct mt9m114 *sensor, |
1130 | const struct v4l2_mbus_framefmt *format) |
1131 | { |
1132 | unsigned int max_blank; |
1133 | |
1134 | /* Update the blanking controls ranges based on the output size. */ |
1135 | max_blank = MT9M114_CAM_SENSOR_CFG_LINE_LENGTH_PCK_MAX |
1136 | - format->width; |
1137 | __v4l2_ctrl_modify_range(ctrl: sensor->pa.hblank, MT9M114_MIN_HBLANK, |
1138 | max: max_blank, step: 1, MT9M114_DEF_HBLANK); |
1139 | |
1140 | max_blank = MT9M114_CAM_SENSOR_CFG_FRAME_LENGTH_LINES_MAX |
1141 | - format->height; |
1142 | __v4l2_ctrl_modify_range(ctrl: sensor->pa.vblank, MT9M114_MIN_VBLANK, |
1143 | max: max_blank, step: 1, MT9M114_DEF_VBLANK); |
1144 | } |
1145 | |
1146 | /* ----------------------------------------------------------------------------- |
1147 | * Pixel Array Subdev Operations |
1148 | */ |
1149 | |
1150 | static inline struct mt9m114 *pa_to_mt9m114(struct v4l2_subdev *sd) |
1151 | { |
1152 | return container_of(sd, struct mt9m114, pa.sd); |
1153 | } |
1154 | |
1155 | static int mt9m114_pa_init_state(struct v4l2_subdev *sd, |
1156 | struct v4l2_subdev_state *state) |
1157 | { |
1158 | struct v4l2_mbus_framefmt *format; |
1159 | struct v4l2_rect *crop; |
1160 | |
1161 | crop = v4l2_subdev_state_get_crop(state, 0); |
1162 | |
1163 | crop->left = 0; |
1164 | crop->top = 0; |
1165 | crop->width = MT9M114_PIXEL_ARRAY_WIDTH; |
1166 | crop->height = MT9M114_PIXEL_ARRAY_HEIGHT; |
1167 | |
1168 | format = v4l2_subdev_state_get_format(state, 0); |
1169 | |
1170 | format->width = MT9M114_PIXEL_ARRAY_WIDTH; |
1171 | format->height = MT9M114_PIXEL_ARRAY_HEIGHT; |
1172 | format->code = MEDIA_BUS_FMT_SGRBG10_1X10; |
1173 | format->field = V4L2_FIELD_NONE; |
1174 | format->colorspace = V4L2_COLORSPACE_RAW; |
1175 | format->ycbcr_enc = V4L2_YCBCR_ENC_601; |
1176 | format->quantization = V4L2_QUANTIZATION_FULL_RANGE; |
1177 | format->xfer_func = V4L2_XFER_FUNC_NONE; |
1178 | |
1179 | return 0; |
1180 | } |
1181 | |
1182 | static int mt9m114_pa_enum_mbus_code(struct v4l2_subdev *sd, |
1183 | struct v4l2_subdev_state *state, |
1184 | struct v4l2_subdev_mbus_code_enum *code) |
1185 | { |
1186 | if (code->index > 0) |
1187 | return -EINVAL; |
1188 | |
1189 | code->code = MEDIA_BUS_FMT_SGRBG10_1X10; |
1190 | |
1191 | return 0; |
1192 | } |
1193 | |
1194 | static int mt9m114_pa_enum_framesizes(struct v4l2_subdev *sd, |
1195 | struct v4l2_subdev_state *state, |
1196 | struct v4l2_subdev_frame_size_enum *fse) |
1197 | { |
1198 | if (fse->index > 1) |
1199 | return -EINVAL; |
1200 | |
1201 | if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10) |
1202 | return -EINVAL; |
1203 | |
1204 | /* Report binning capability through frame size enumeration. */ |
1205 | fse->min_width = MT9M114_PIXEL_ARRAY_WIDTH / (fse->index + 1); |
1206 | fse->max_width = MT9M114_PIXEL_ARRAY_WIDTH / (fse->index + 1); |
1207 | fse->min_height = MT9M114_PIXEL_ARRAY_HEIGHT / (fse->index + 1); |
1208 | fse->max_height = MT9M114_PIXEL_ARRAY_HEIGHT / (fse->index + 1); |
1209 | |
1210 | return 0; |
1211 | } |
1212 | |
1213 | static int mt9m114_pa_set_fmt(struct v4l2_subdev *sd, |
1214 | struct v4l2_subdev_state *state, |
1215 | struct v4l2_subdev_format *fmt) |
1216 | { |
1217 | struct mt9m114 *sensor = pa_to_mt9m114(sd); |
1218 | struct v4l2_mbus_framefmt *format; |
1219 | struct v4l2_rect *crop; |
1220 | unsigned int hscale; |
1221 | unsigned int vscale; |
1222 | |
1223 | crop = v4l2_subdev_state_get_crop(state, fmt->pad); |
1224 | format = v4l2_subdev_state_get_format(state, fmt->pad); |
1225 | |
1226 | /* The sensor can bin horizontally and vertically. */ |
1227 | hscale = DIV_ROUND_CLOSEST(crop->width, fmt->format.width ? : 1); |
1228 | vscale = DIV_ROUND_CLOSEST(crop->height, fmt->format.height ? : 1); |
1229 | format->width = crop->width / clamp(hscale, 1U, 2U); |
1230 | format->height = crop->height / clamp(vscale, 1U, 2U); |
1231 | |
1232 | fmt->format = *format; |
1233 | |
1234 | if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) |
1235 | mt9m114_pa_ctrl_update_blanking(sensor, format); |
1236 | |
1237 | return 0; |
1238 | } |
1239 | |
1240 | static int mt9m114_pa_get_selection(struct v4l2_subdev *sd, |
1241 | struct v4l2_subdev_state *state, |
1242 | struct v4l2_subdev_selection *sel) |
1243 | { |
1244 | switch (sel->target) { |
1245 | case V4L2_SEL_TGT_CROP: |
1246 | sel->r = *v4l2_subdev_state_get_crop(state, sel->pad); |
1247 | return 0; |
1248 | |
1249 | case V4L2_SEL_TGT_CROP_DEFAULT: |
1250 | case V4L2_SEL_TGT_CROP_BOUNDS: |
1251 | case V4L2_SEL_TGT_NATIVE_SIZE: |
1252 | sel->r.left = 0; |
1253 | sel->r.top = 0; |
1254 | sel->r.width = MT9M114_PIXEL_ARRAY_WIDTH; |
1255 | sel->r.height = MT9M114_PIXEL_ARRAY_HEIGHT; |
1256 | return 0; |
1257 | |
1258 | default: |
1259 | return -EINVAL; |
1260 | } |
1261 | } |
1262 | |
1263 | static int mt9m114_pa_set_selection(struct v4l2_subdev *sd, |
1264 | struct v4l2_subdev_state *state, |
1265 | struct v4l2_subdev_selection *sel) |
1266 | { |
1267 | struct mt9m114 *sensor = pa_to_mt9m114(sd); |
1268 | struct v4l2_mbus_framefmt *format; |
1269 | struct v4l2_rect *crop; |
1270 | |
1271 | if (sel->target != V4L2_SEL_TGT_CROP) |
1272 | return -EINVAL; |
1273 | |
1274 | crop = v4l2_subdev_state_get_crop(state, sel->pad); |
1275 | format = v4l2_subdev_state_get_format(state, sel->pad); |
1276 | |
1277 | /* |
1278 | * Clamp the crop rectangle. The vertical coordinates must be even, and |
1279 | * the horizontal coordinates must be a multiple of 4. |
1280 | * |
1281 | * FIXME: The horizontal coordinates must be a multiple of 8 when |
1282 | * binning, but binning is configured after setting the selection, so |
1283 | * we can't know tell here if it will be used. |
1284 | */ |
1285 | crop->left = ALIGN(sel->r.left, 4); |
1286 | crop->top = ALIGN(sel->r.top, 2); |
1287 | crop->width = clamp_t(unsigned int, ALIGN(sel->r.width, 4), |
1288 | MT9M114_PIXEL_ARRAY_MIN_OUTPUT_WIDTH, |
1289 | MT9M114_PIXEL_ARRAY_WIDTH - crop->left); |
1290 | crop->height = clamp_t(unsigned int, ALIGN(sel->r.height, 2), |
1291 | MT9M114_PIXEL_ARRAY_MIN_OUTPUT_HEIGHT, |
1292 | MT9M114_PIXEL_ARRAY_HEIGHT - crop->top); |
1293 | |
1294 | sel->r = *crop; |
1295 | |
1296 | /* Reset the format. */ |
1297 | format->width = crop->width; |
1298 | format->height = crop->height; |
1299 | |
1300 | if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) |
1301 | mt9m114_pa_ctrl_update_blanking(sensor, format); |
1302 | |
1303 | return 0; |
1304 | } |
1305 | |
1306 | static const struct v4l2_subdev_pad_ops mt9m114_pa_pad_ops = { |
1307 | .enum_mbus_code = mt9m114_pa_enum_mbus_code, |
1308 | .enum_frame_size = mt9m114_pa_enum_framesizes, |
1309 | .get_fmt = v4l2_subdev_get_fmt, |
1310 | .set_fmt = mt9m114_pa_set_fmt, |
1311 | .get_selection = mt9m114_pa_get_selection, |
1312 | .set_selection = mt9m114_pa_set_selection, |
1313 | }; |
1314 | |
1315 | static const struct v4l2_subdev_ops mt9m114_pa_ops = { |
1316 | .pad = &mt9m114_pa_pad_ops, |
1317 | }; |
1318 | |
1319 | static const struct v4l2_subdev_internal_ops mt9m114_pa_internal_ops = { |
1320 | .init_state = mt9m114_pa_init_state, |
1321 | }; |
1322 | |
1323 | static int mt9m114_pa_init(struct mt9m114 *sensor) |
1324 | { |
1325 | struct v4l2_ctrl_handler *hdl = &sensor->pa.hdl; |
1326 | struct v4l2_subdev *sd = &sensor->pa.sd; |
1327 | struct media_pad *pads = &sensor->pa.pad; |
1328 | const struct v4l2_mbus_framefmt *format; |
1329 | struct v4l2_subdev_state *state; |
1330 | unsigned int max_exposure; |
1331 | int ret; |
1332 | |
1333 | /* Initialize the subdev. */ |
1334 | v4l2_subdev_init(sd, ops: &mt9m114_pa_ops); |
1335 | sd->internal_ops = &mt9m114_pa_internal_ops; |
1336 | v4l2_i2c_subdev_set_name(sd, client: sensor->client, NULL, postfix: " pixel array"); |
1337 | |
1338 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; |
1339 | sd->owner = THIS_MODULE; |
1340 | sd->dev = &sensor->client->dev; |
1341 | v4l2_set_subdevdata(sd, p: sensor->client); |
1342 | |
1343 | /* Initialize the media entity. */ |
1344 | sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; |
1345 | sd->entity.ops = &mt9m114_entity_ops; |
1346 | pads[0].flags = MEDIA_PAD_FL_SOURCE; |
1347 | ret = media_entity_pads_init(entity: &sd->entity, num_pads: 1, pads); |
1348 | if (ret < 0) |
1349 | return ret; |
1350 | |
1351 | /* Initialize the control handler. */ |
1352 | v4l2_ctrl_handler_init(hdl, 7); |
1353 | |
1354 | /* The range of the HBLANK and VBLANK controls will be updated below. */ |
1355 | sensor->pa.hblank = v4l2_ctrl_new_std(hdl, ops: &mt9m114_pa_ctrl_ops, |
1356 | V4L2_CID_HBLANK, |
1357 | MT9M114_DEF_HBLANK, |
1358 | MT9M114_DEF_HBLANK, step: 1, |
1359 | MT9M114_DEF_HBLANK); |
1360 | sensor->pa.vblank = v4l2_ctrl_new_std(hdl, ops: &mt9m114_pa_ctrl_ops, |
1361 | V4L2_CID_VBLANK, |
1362 | MT9M114_DEF_VBLANK, |
1363 | MT9M114_DEF_VBLANK, step: 1, |
1364 | MT9M114_DEF_VBLANK); |
1365 | |
1366 | /* |
1367 | * The maximum coarse integration time is the frame length in lines |
1368 | * minus two. The default is taken directly from the datasheet, but |
1369 | * makes little sense as auto-exposure is enabled by default. |
1370 | */ |
1371 | max_exposure = MT9M114_PIXEL_ARRAY_HEIGHT + MT9M114_MIN_VBLANK - 2; |
1372 | sensor->pa.exposure = v4l2_ctrl_new_std(hdl, ops: &mt9m114_pa_ctrl_ops, |
1373 | V4L2_CID_EXPOSURE, min: 1, |
1374 | max: max_exposure, step: 1, def: 16); |
1375 | if (sensor->pa.exposure) |
1376 | sensor->pa.exposure->flags |= V4L2_CTRL_FLAG_VOLATILE; |
1377 | |
1378 | sensor->pa.gain = v4l2_ctrl_new_std(hdl, ops: &mt9m114_pa_ctrl_ops, |
1379 | V4L2_CID_ANALOGUE_GAIN, min: 1, |
1380 | max: 511, step: 1, def: 32); |
1381 | if (sensor->pa.gain) |
1382 | sensor->pa.gain->flags |= V4L2_CTRL_FLAG_VOLATILE; |
1383 | |
1384 | v4l2_ctrl_new_std(hdl, ops: &mt9m114_pa_ctrl_ops, |
1385 | V4L2_CID_PIXEL_RATE, |
1386 | min: sensor->pixrate, max: sensor->pixrate, step: 1, |
1387 | def: sensor->pixrate); |
1388 | |
1389 | v4l2_ctrl_new_std(hdl, ops: &mt9m114_pa_ctrl_ops, |
1390 | V4L2_CID_HFLIP, |
1391 | min: 0, max: 1, step: 1, def: 0); |
1392 | v4l2_ctrl_new_std(hdl, ops: &mt9m114_pa_ctrl_ops, |
1393 | V4L2_CID_VFLIP, |
1394 | min: 0, max: 1, step: 1, def: 0); |
1395 | |
1396 | if (hdl->error) { |
1397 | ret = hdl->error; |
1398 | goto error; |
1399 | } |
1400 | |
1401 | sd->state_lock = hdl->lock; |
1402 | |
1403 | ret = v4l2_subdev_init_finalize(sd); |
1404 | if (ret) |
1405 | goto error; |
1406 | |
1407 | /* Update the range of the blanking controls based on the format. */ |
1408 | state = v4l2_subdev_lock_and_get_active_state(sd); |
1409 | format = v4l2_subdev_state_get_format(state, 0); |
1410 | mt9m114_pa_ctrl_update_blanking(sensor, format); |
1411 | v4l2_subdev_unlock_state(state); |
1412 | |
1413 | sd->ctrl_handler = hdl; |
1414 | |
1415 | return 0; |
1416 | |
1417 | error: |
1418 | v4l2_ctrl_handler_free(hdl: &sensor->pa.hdl); |
1419 | media_entity_cleanup(entity: &sensor->pa.sd.entity); |
1420 | return ret; |
1421 | } |
1422 | |
1423 | static void mt9m114_pa_cleanup(struct mt9m114 *sensor) |
1424 | { |
1425 | v4l2_ctrl_handler_free(hdl: &sensor->pa.hdl); |
1426 | media_entity_cleanup(entity: &sensor->pa.sd.entity); |
1427 | } |
1428 | |
1429 | /* ----------------------------------------------------------------------------- |
1430 | * Image Flow Processor Control Operations |
1431 | */ |
1432 | |
1433 | static const char * const mt9m114_test_pattern_menu[] = { |
1434 | "Disabled", |
1435 | "Solid Color", |
1436 | "100% Color Bars", |
1437 | "Pseudo-Random", |
1438 | "Fade-to-Gray Color Bars", |
1439 | "Walking Ones 10-bit", |
1440 | "Walking Ones 8-bit", |
1441 | }; |
1442 | |
1443 | /* Keep in sync with mt9m114_test_pattern_menu */ |
1444 | static const unsigned int mt9m114_test_pattern_value[] = { |
1445 | MT9M114_CAM_MODE_TEST_PATTERN_SELECT_SOLID, |
1446 | MT9M114_CAM_MODE_TEST_PATTERN_SELECT_SOLID_BARS, |
1447 | MT9M114_CAM_MODE_TEST_PATTERN_SELECT_RANDOM, |
1448 | MT9M114_CAM_MODE_TEST_PATTERN_SELECT_FADING_BARS, |
1449 | MT9M114_CAM_MODE_TEST_PATTERN_SELECT_WALKING_1S_10B, |
1450 | MT9M114_CAM_MODE_TEST_PATTERN_SELECT_WALKING_1S_8B, |
1451 | }; |
1452 | |
1453 | static inline struct mt9m114 *ifp_ctrl_to_mt9m114(struct v4l2_ctrl *ctrl) |
1454 | { |
1455 | return container_of(ctrl->handler, struct mt9m114, ifp.hdl); |
1456 | } |
1457 | |
1458 | static int mt9m114_ifp_s_ctrl(struct v4l2_ctrl *ctrl) |
1459 | { |
1460 | struct mt9m114 *sensor = ifp_ctrl_to_mt9m114(ctrl); |
1461 | u32 value; |
1462 | int ret = 0; |
1463 | |
1464 | if (ctrl->id == V4L2_CID_EXPOSURE_AUTO) |
1465 | mt9m114_pa_ctrl_update_exposure(sensor, |
1466 | manual: ctrl->val != V4L2_EXPOSURE_AUTO); |
1467 | |
1468 | /* V4L2 controls values are applied only when power is up. */ |
1469 | if (!pm_runtime_get_if_in_use(dev: &sensor->client->dev)) |
1470 | return 0; |
1471 | |
1472 | switch (ctrl->id) { |
1473 | case V4L2_CID_AUTO_WHITE_BALANCE: |
1474 | /* Control both the AWB mode and the CCM algorithm. */ |
1475 | if (ctrl->val) |
1476 | value = MT9M114_CAM_AWB_MODE_AUTO |
1477 | | MT9M114_CAM_AWB_MODE_EXCLUSIVE_AE; |
1478 | else |
1479 | value = 0; |
1480 | |
1481 | cci_write(map: sensor->regmap, MT9M114_CAM_AWB_AWBMODE, val: value, err: &ret); |
1482 | |
1483 | if (ctrl->val) |
1484 | value = MT9M114_CCM_EXEC_CALC_CCM_MATRIX | 0x22; |
1485 | else |
1486 | value = 0; |
1487 | |
1488 | cci_write(map: sensor->regmap, MT9M114_CCM_ALGO, val: value, err: &ret); |
1489 | break; |
1490 | |
1491 | case V4L2_CID_EXPOSURE_AUTO: |
1492 | if (ctrl->val == V4L2_EXPOSURE_AUTO) |
1493 | value = MT9M114_AE_TRACK_EXEC_AUTOMATIC_EXPOSURE |
1494 | | 0x00fe; |
1495 | else |
1496 | value = 0; |
1497 | |
1498 | cci_write(map: sensor->regmap, MT9M114_AE_TRACK_ALGO, val: value, err: &ret); |
1499 | if (ret) |
1500 | break; |
1501 | |
1502 | break; |
1503 | |
1504 | case V4L2_CID_TEST_PATTERN: |
1505 | case V4L2_CID_TEST_PATTERN_RED: |
1506 | case V4L2_CID_TEST_PATTERN_GREENR: |
1507 | case V4L2_CID_TEST_PATTERN_BLUE: { |
1508 | unsigned int pattern = sensor->ifp.tpg[MT9M114_TPG_PATTERN]->val; |
1509 | |
1510 | if (pattern) { |
1511 | cci_write(map: sensor->regmap, MT9M114_CAM_MODE_SELECT, |
1512 | MT9M114_CAM_MODE_SELECT_TEST_PATTERN, err: &ret); |
1513 | cci_write(map: sensor->regmap, |
1514 | MT9M114_CAM_MODE_TEST_PATTERN_SELECT, |
1515 | val: mt9m114_test_pattern_value[pattern - 1], err: &ret); |
1516 | cci_write(map: sensor->regmap, |
1517 | MT9M114_CAM_MODE_TEST_PATTERN_RED, |
1518 | val: sensor->ifp.tpg[MT9M114_TPG_RED]->val, err: &ret); |
1519 | cci_write(map: sensor->regmap, |
1520 | MT9M114_CAM_MODE_TEST_PATTERN_GREEN, |
1521 | val: sensor->ifp.tpg[MT9M114_TPG_GREEN]->val, err: &ret); |
1522 | cci_write(map: sensor->regmap, |
1523 | MT9M114_CAM_MODE_TEST_PATTERN_BLUE, |
1524 | val: sensor->ifp.tpg[MT9M114_TPG_BLUE]->val, err: &ret); |
1525 | } else { |
1526 | cci_write(map: sensor->regmap, MT9M114_CAM_MODE_SELECT, |
1527 | MT9M114_CAM_MODE_SELECT_NORMAL, err: &ret); |
1528 | } |
1529 | |
1530 | /* |
1531 | * A Config-Change needs to be issued for the change to take |
1532 | * effect. If we're not streaming ignore this, the change will |
1533 | * be applied when the stream is started. |
1534 | */ |
1535 | if (ret || !sensor->streaming) |
1536 | break; |
1537 | |
1538 | ret = mt9m114_set_state(sensor, |
1539 | MT9M114_SYS_STATE_ENTER_CONFIG_CHANGE); |
1540 | break; |
1541 | } |
1542 | |
1543 | default: |
1544 | ret = -EINVAL; |
1545 | break; |
1546 | } |
1547 | |
1548 | pm_runtime_mark_last_busy(dev: &sensor->client->dev); |
1549 | pm_runtime_put_autosuspend(dev: &sensor->client->dev); |
1550 | |
1551 | return ret; |
1552 | } |
1553 | |
1554 | static const struct v4l2_ctrl_ops mt9m114_ifp_ctrl_ops = { |
1555 | .s_ctrl = mt9m114_ifp_s_ctrl, |
1556 | }; |
1557 | |
1558 | /* ----------------------------------------------------------------------------- |
1559 | * Image Flow Processor Subdev Operations |
1560 | */ |
1561 | |
1562 | static inline struct mt9m114 *ifp_to_mt9m114(struct v4l2_subdev *sd) |
1563 | { |
1564 | return container_of(sd, struct mt9m114, ifp.sd); |
1565 | } |
1566 | |
1567 | static int mt9m114_ifp_s_stream(struct v4l2_subdev *sd, int enable) |
1568 | { |
1569 | struct mt9m114 *sensor = ifp_to_mt9m114(sd); |
1570 | struct v4l2_subdev_state *pa_state; |
1571 | struct v4l2_subdev_state *ifp_state; |
1572 | int ret; |
1573 | |
1574 | if (!enable) |
1575 | return mt9m114_stop_streaming(sensor); |
1576 | |
1577 | ifp_state = v4l2_subdev_lock_and_get_active_state(sd: &sensor->ifp.sd); |
1578 | pa_state = v4l2_subdev_lock_and_get_active_state(sd: &sensor->pa.sd); |
1579 | |
1580 | ret = mt9m114_start_streaming(sensor, pa_state, ifp_state); |
1581 | |
1582 | v4l2_subdev_unlock_state(state: pa_state); |
1583 | v4l2_subdev_unlock_state(state: ifp_state); |
1584 | |
1585 | return ret; |
1586 | } |
1587 | |
1588 | static int mt9m114_ifp_get_frame_interval(struct v4l2_subdev *sd, |
1589 | struct v4l2_subdev_state *sd_state, |
1590 | struct v4l2_subdev_frame_interval *interval) |
1591 | { |
1592 | struct v4l2_fract *ival = &interval->interval; |
1593 | struct mt9m114 *sensor = ifp_to_mt9m114(sd); |
1594 | |
1595 | /* |
1596 | * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2 |
1597 | * subdev active state API. |
1598 | */ |
1599 | if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE) |
1600 | return -EINVAL; |
1601 | |
1602 | mutex_lock(sensor->ifp.hdl.lock); |
1603 | |
1604 | ival->numerator = 1; |
1605 | ival->denominator = sensor->ifp.frame_rate; |
1606 | |
1607 | mutex_unlock(lock: sensor->ifp.hdl.lock); |
1608 | |
1609 | return 0; |
1610 | } |
1611 | |
1612 | static int mt9m114_ifp_set_frame_interval(struct v4l2_subdev *sd, |
1613 | struct v4l2_subdev_state *sd_state, |
1614 | struct v4l2_subdev_frame_interval *interval) |
1615 | { |
1616 | struct v4l2_fract *ival = &interval->interval; |
1617 | struct mt9m114 *sensor = ifp_to_mt9m114(sd); |
1618 | int ret = 0; |
1619 | |
1620 | /* |
1621 | * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2 |
1622 | * subdev active state API. |
1623 | */ |
1624 | if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE) |
1625 | return -EINVAL; |
1626 | |
1627 | mutex_lock(sensor->ifp.hdl.lock); |
1628 | |
1629 | if (ival->numerator != 0 && ival->denominator != 0) |
1630 | sensor->ifp.frame_rate = min_t(unsigned int, |
1631 | ival->denominator / ival->numerator, |
1632 | MT9M114_MAX_FRAME_RATE); |
1633 | else |
1634 | sensor->ifp.frame_rate = MT9M114_MAX_FRAME_RATE; |
1635 | |
1636 | ival->numerator = 1; |
1637 | ival->denominator = sensor->ifp.frame_rate; |
1638 | |
1639 | if (sensor->streaming) |
1640 | ret = mt9m114_set_frame_rate(sensor); |
1641 | |
1642 | mutex_unlock(lock: sensor->ifp.hdl.lock); |
1643 | |
1644 | return ret; |
1645 | } |
1646 | |
1647 | static int mt9m114_ifp_init_state(struct v4l2_subdev *sd, |
1648 | struct v4l2_subdev_state *state) |
1649 | { |
1650 | struct mt9m114 *sensor = ifp_to_mt9m114(sd); |
1651 | struct v4l2_mbus_framefmt *format; |
1652 | struct v4l2_rect *crop; |
1653 | struct v4l2_rect *compose; |
1654 | |
1655 | format = v4l2_subdev_state_get_format(state, 0); |
1656 | |
1657 | format->width = MT9M114_PIXEL_ARRAY_WIDTH; |
1658 | format->height = MT9M114_PIXEL_ARRAY_HEIGHT; |
1659 | format->code = MEDIA_BUS_FMT_SGRBG10_1X10; |
1660 | format->field = V4L2_FIELD_NONE; |
1661 | format->colorspace = V4L2_COLORSPACE_RAW; |
1662 | format->ycbcr_enc = V4L2_YCBCR_ENC_601; |
1663 | format->quantization = V4L2_QUANTIZATION_FULL_RANGE; |
1664 | format->xfer_func = V4L2_XFER_FUNC_NONE; |
1665 | |
1666 | crop = v4l2_subdev_state_get_crop(state, 0); |
1667 | |
1668 | crop->left = 4; |
1669 | crop->top = 4; |
1670 | crop->width = format->width - 8; |
1671 | crop->height = format->height - 8; |
1672 | |
1673 | compose = v4l2_subdev_state_get_compose(state, 0); |
1674 | |
1675 | compose->left = 0; |
1676 | compose->top = 0; |
1677 | compose->width = crop->width; |
1678 | compose->height = crop->height; |
1679 | |
1680 | format = v4l2_subdev_state_get_format(state, 1); |
1681 | |
1682 | format->width = compose->width; |
1683 | format->height = compose->height; |
1684 | format->code = mt9m114_default_format_info(sensor)->code; |
1685 | format->field = V4L2_FIELD_NONE; |
1686 | format->colorspace = V4L2_COLORSPACE_SRGB; |
1687 | format->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; |
1688 | format->quantization = V4L2_QUANTIZATION_DEFAULT; |
1689 | format->xfer_func = V4L2_XFER_FUNC_DEFAULT; |
1690 | |
1691 | return 0; |
1692 | } |
1693 | |
1694 | static int mt9m114_ifp_enum_mbus_code(struct v4l2_subdev *sd, |
1695 | struct v4l2_subdev_state *state, |
1696 | struct v4l2_subdev_mbus_code_enum *code) |
1697 | { |
1698 | const unsigned int num_formats = ARRAY_SIZE(mt9m114_format_infos); |
1699 | struct mt9m114 *sensor = ifp_to_mt9m114(sd); |
1700 | unsigned int index = 0; |
1701 | unsigned int flag; |
1702 | unsigned int i; |
1703 | |
1704 | switch (code->pad) { |
1705 | case 0: |
1706 | if (code->index != 0) |
1707 | return -EINVAL; |
1708 | |
1709 | code->code = mt9m114_format_infos[num_formats - 1].code; |
1710 | return 0; |
1711 | |
1712 | case 1: |
1713 | if (sensor->bus_cfg.bus_type == V4L2_MBUS_CSI2_DPHY) |
1714 | flag = MT9M114_FMT_FLAG_CSI2; |
1715 | else |
1716 | flag = MT9M114_FMT_FLAG_PARALLEL; |
1717 | |
1718 | for (i = 0; i < num_formats; ++i) { |
1719 | const struct mt9m114_format_info *info = |
1720 | &mt9m114_format_infos[i]; |
1721 | |
1722 | if (info->flags & flag) { |
1723 | if (index == code->index) { |
1724 | code->code = info->code; |
1725 | return 0; |
1726 | } |
1727 | |
1728 | index++; |
1729 | } |
1730 | } |
1731 | |
1732 | return -EINVAL; |
1733 | |
1734 | default: |
1735 | return -EINVAL; |
1736 | } |
1737 | } |
1738 | |
1739 | static int mt9m114_ifp_enum_framesizes(struct v4l2_subdev *sd, |
1740 | struct v4l2_subdev_state *state, |
1741 | struct v4l2_subdev_frame_size_enum *fse) |
1742 | { |
1743 | struct mt9m114 *sensor = ifp_to_mt9m114(sd); |
1744 | const struct mt9m114_format_info *info; |
1745 | |
1746 | if (fse->index > 0) |
1747 | return -EINVAL; |
1748 | |
1749 | info = mt9m114_format_info(sensor, pad: fse->pad, code: fse->code); |
1750 | if (!info || info->code != fse->code) |
1751 | return -EINVAL; |
1752 | |
1753 | if (fse->pad == 0) { |
1754 | fse->min_width = MT9M114_PIXEL_ARRAY_MIN_OUTPUT_WIDTH; |
1755 | fse->max_width = MT9M114_PIXEL_ARRAY_WIDTH; |
1756 | fse->min_height = MT9M114_PIXEL_ARRAY_MIN_OUTPUT_HEIGHT; |
1757 | fse->max_height = MT9M114_PIXEL_ARRAY_HEIGHT; |
1758 | } else { |
1759 | const struct v4l2_rect *crop; |
1760 | |
1761 | crop = v4l2_subdev_state_get_crop(state, 0); |
1762 | |
1763 | fse->max_width = crop->width; |
1764 | fse->max_height = crop->height; |
1765 | |
1766 | fse->min_width = fse->max_width / 4; |
1767 | fse->min_height = fse->max_height / 4; |
1768 | } |
1769 | |
1770 | return 0; |
1771 | } |
1772 | |
1773 | static int mt9m114_ifp_enum_frameintervals(struct v4l2_subdev *sd, |
1774 | struct v4l2_subdev_state *state, |
1775 | struct v4l2_subdev_frame_interval_enum *fie) |
1776 | { |
1777 | struct mt9m114 *sensor = ifp_to_mt9m114(sd); |
1778 | const struct mt9m114_format_info *info; |
1779 | |
1780 | if (fie->index > 0) |
1781 | return -EINVAL; |
1782 | |
1783 | info = mt9m114_format_info(sensor, pad: fie->pad, code: fie->code); |
1784 | if (!info || info->code != fie->code) |
1785 | return -EINVAL; |
1786 | |
1787 | fie->interval.numerator = 1; |
1788 | fie->interval.denominator = MT9M114_MAX_FRAME_RATE; |
1789 | |
1790 | return 0; |
1791 | } |
1792 | |
1793 | static int mt9m114_ifp_set_fmt(struct v4l2_subdev *sd, |
1794 | struct v4l2_subdev_state *state, |
1795 | struct v4l2_subdev_format *fmt) |
1796 | { |
1797 | struct mt9m114 *sensor = ifp_to_mt9m114(sd); |
1798 | struct v4l2_mbus_framefmt *format; |
1799 | |
1800 | format = v4l2_subdev_state_get_format(state, fmt->pad); |
1801 | |
1802 | if (fmt->pad == 0) { |
1803 | /* Only the size can be changed on the sink pad. */ |
1804 | format->width = clamp(ALIGN(fmt->format.width, 8), |
1805 | MT9M114_PIXEL_ARRAY_MIN_OUTPUT_WIDTH, |
1806 | MT9M114_PIXEL_ARRAY_WIDTH); |
1807 | format->height = clamp(ALIGN(fmt->format.height, 8), |
1808 | MT9M114_PIXEL_ARRAY_MIN_OUTPUT_HEIGHT, |
1809 | MT9M114_PIXEL_ARRAY_HEIGHT); |
1810 | } else { |
1811 | const struct mt9m114_format_info *info; |
1812 | |
1813 | /* Only the media bus code can be changed on the source pad. */ |
1814 | info = mt9m114_format_info(sensor, pad: 1, code: fmt->format.code); |
1815 | |
1816 | format->code = info->code; |
1817 | |
1818 | /* If the output format is RAW10, bypass the scaler. */ |
1819 | if (format->code == MEDIA_BUS_FMT_SGRBG10_1X10) |
1820 | *format = *v4l2_subdev_state_get_format(state, 0); |
1821 | } |
1822 | |
1823 | fmt->format = *format; |
1824 | |
1825 | return 0; |
1826 | } |
1827 | |
1828 | static int mt9m114_ifp_get_selection(struct v4l2_subdev *sd, |
1829 | struct v4l2_subdev_state *state, |
1830 | struct v4l2_subdev_selection *sel) |
1831 | { |
1832 | const struct v4l2_mbus_framefmt *format; |
1833 | const struct v4l2_rect *crop; |
1834 | int ret = 0; |
1835 | |
1836 | /* Crop and compose are only supported on the sink pad. */ |
1837 | if (sel->pad != 0) |
1838 | return -EINVAL; |
1839 | |
1840 | switch (sel->target) { |
1841 | case V4L2_SEL_TGT_CROP: |
1842 | sel->r = *v4l2_subdev_state_get_crop(state, 0); |
1843 | break; |
1844 | |
1845 | case V4L2_SEL_TGT_CROP_DEFAULT: |
1846 | case V4L2_SEL_TGT_CROP_BOUNDS: |
1847 | /* |
1848 | * The crop default and bounds are equal to the sink |
1849 | * format size minus 4 pixels on each side for demosaicing. |
1850 | */ |
1851 | format = v4l2_subdev_state_get_format(state, 0); |
1852 | |
1853 | sel->r.left = 4; |
1854 | sel->r.top = 4; |
1855 | sel->r.width = format->width - 8; |
1856 | sel->r.height = format->height - 8; |
1857 | break; |
1858 | |
1859 | case V4L2_SEL_TGT_COMPOSE: |
1860 | sel->r = *v4l2_subdev_state_get_compose(state, 0); |
1861 | break; |
1862 | |
1863 | case V4L2_SEL_TGT_COMPOSE_DEFAULT: |
1864 | case V4L2_SEL_TGT_COMPOSE_BOUNDS: |
1865 | /* |
1866 | * The compose default and bounds sizes are equal to the sink |
1867 | * crop rectangle size. |
1868 | */ |
1869 | crop = v4l2_subdev_state_get_crop(state, 0); |
1870 | sel->r.left = 0; |
1871 | sel->r.top = 0; |
1872 | sel->r.width = crop->width; |
1873 | sel->r.height = crop->height; |
1874 | break; |
1875 | |
1876 | default: |
1877 | ret = -EINVAL; |
1878 | break; |
1879 | } |
1880 | |
1881 | return ret; |
1882 | } |
1883 | |
1884 | static int mt9m114_ifp_set_selection(struct v4l2_subdev *sd, |
1885 | struct v4l2_subdev_state *state, |
1886 | struct v4l2_subdev_selection *sel) |
1887 | { |
1888 | struct v4l2_mbus_framefmt *format; |
1889 | struct v4l2_rect *crop; |
1890 | struct v4l2_rect *compose; |
1891 | |
1892 | if (sel->target != V4L2_SEL_TGT_CROP && |
1893 | sel->target != V4L2_SEL_TGT_COMPOSE) |
1894 | return -EINVAL; |
1895 | |
1896 | /* Crop and compose are only supported on the sink pad. */ |
1897 | if (sel->pad != 0) |
1898 | return -EINVAL; |
1899 | |
1900 | format = v4l2_subdev_state_get_format(state, 0); |
1901 | crop = v4l2_subdev_state_get_crop(state, 0); |
1902 | compose = v4l2_subdev_state_get_compose(state, 0); |
1903 | |
1904 | if (sel->target == V4L2_SEL_TGT_CROP) { |
1905 | /* |
1906 | * Clamp the crop rectangle. Demosaicing removes 4 pixels on |
1907 | * each side of the image. |
1908 | */ |
1909 | crop->left = clamp_t(unsigned int, ALIGN(sel->r.left, 2), 4, |
1910 | format->width - 4 - |
1911 | MT9M114_SCALER_CROPPED_INPUT_WIDTH); |
1912 | crop->top = clamp_t(unsigned int, ALIGN(sel->r.top, 2), 4, |
1913 | format->height - 4 - |
1914 | MT9M114_SCALER_CROPPED_INPUT_HEIGHT); |
1915 | crop->width = clamp_t(unsigned int, ALIGN(sel->r.width, 2), |
1916 | MT9M114_SCALER_CROPPED_INPUT_WIDTH, |
1917 | format->width - 4 - crop->left); |
1918 | crop->height = clamp_t(unsigned int, ALIGN(sel->r.height, 2), |
1919 | MT9M114_SCALER_CROPPED_INPUT_HEIGHT, |
1920 | format->height - 4 - crop->top); |
1921 | |
1922 | sel->r = *crop; |
1923 | |
1924 | /* Propagate to the compose rectangle. */ |
1925 | compose->width = crop->width; |
1926 | compose->height = crop->height; |
1927 | } else { |
1928 | /* |
1929 | * Clamp the compose rectangle. The scaler can only downscale. |
1930 | */ |
1931 | compose->left = 0; |
1932 | compose->top = 0; |
1933 | compose->width = clamp_t(unsigned int, ALIGN(sel->r.width, 2), |
1934 | MT9M114_SCALER_CROPPED_INPUT_WIDTH, |
1935 | crop->width); |
1936 | compose->height = clamp_t(unsigned int, ALIGN(sel->r.height, 2), |
1937 | MT9M114_SCALER_CROPPED_INPUT_HEIGHT, |
1938 | crop->height); |
1939 | |
1940 | sel->r = *compose; |
1941 | } |
1942 | |
1943 | /* Propagate the compose rectangle to the source format. */ |
1944 | format = v4l2_subdev_state_get_format(state, 1); |
1945 | format->width = compose->width; |
1946 | format->height = compose->height; |
1947 | |
1948 | return 0; |
1949 | } |
1950 | |
1951 | static void mt9m114_ifp_unregistered(struct v4l2_subdev *sd) |
1952 | { |
1953 | struct mt9m114 *sensor = ifp_to_mt9m114(sd); |
1954 | |
1955 | v4l2_device_unregister_subdev(sd: &sensor->pa.sd); |
1956 | } |
1957 | |
1958 | static int mt9m114_ifp_registered(struct v4l2_subdev *sd) |
1959 | { |
1960 | struct mt9m114 *sensor = ifp_to_mt9m114(sd); |
1961 | int ret; |
1962 | |
1963 | ret = v4l2_device_register_subdev(v4l2_dev: sd->v4l2_dev, sd: &sensor->pa.sd); |
1964 | if (ret < 0) { |
1965 | dev_err(&sensor->client->dev, |
1966 | "Failed to register pixel array subdev\n"); |
1967 | return ret; |
1968 | } |
1969 | |
1970 | ret = media_create_pad_link(source: &sensor->pa.sd.entity, source_pad: 0, |
1971 | sink: &sensor->ifp.sd.entity, sink_pad: 0, |
1972 | MEDIA_LNK_FL_ENABLED | |
1973 | MEDIA_LNK_FL_IMMUTABLE); |
1974 | if (ret < 0) { |
1975 | dev_err(&sensor->client->dev, |
1976 | "Failed to link pixel array to ifp\n"); |
1977 | v4l2_device_unregister_subdev(sd: &sensor->pa.sd); |
1978 | return ret; |
1979 | } |
1980 | |
1981 | return 0; |
1982 | } |
1983 | |
1984 | static const struct v4l2_subdev_video_ops mt9m114_ifp_video_ops = { |
1985 | .s_stream = mt9m114_ifp_s_stream, |
1986 | }; |
1987 | |
1988 | static const struct v4l2_subdev_pad_ops mt9m114_ifp_pad_ops = { |
1989 | .enum_mbus_code = mt9m114_ifp_enum_mbus_code, |
1990 | .enum_frame_size = mt9m114_ifp_enum_framesizes, |
1991 | .enum_frame_interval = mt9m114_ifp_enum_frameintervals, |
1992 | .get_fmt = v4l2_subdev_get_fmt, |
1993 | .set_fmt = mt9m114_ifp_set_fmt, |
1994 | .get_selection = mt9m114_ifp_get_selection, |
1995 | .set_selection = mt9m114_ifp_set_selection, |
1996 | .get_frame_interval = mt9m114_ifp_get_frame_interval, |
1997 | .set_frame_interval = mt9m114_ifp_set_frame_interval, |
1998 | }; |
1999 | |
2000 | static const struct v4l2_subdev_ops mt9m114_ifp_ops = { |
2001 | .video = &mt9m114_ifp_video_ops, |
2002 | .pad = &mt9m114_ifp_pad_ops, |
2003 | }; |
2004 | |
2005 | static const struct v4l2_subdev_internal_ops mt9m114_ifp_internal_ops = { |
2006 | .init_state = mt9m114_ifp_init_state, |
2007 | .registered = mt9m114_ifp_registered, |
2008 | .unregistered = mt9m114_ifp_unregistered, |
2009 | }; |
2010 | |
2011 | static int mt9m114_ifp_init(struct mt9m114 *sensor) |
2012 | { |
2013 | struct v4l2_subdev *sd = &sensor->ifp.sd; |
2014 | struct media_pad *pads = sensor->ifp.pads; |
2015 | struct v4l2_ctrl_handler *hdl = &sensor->ifp.hdl; |
2016 | struct v4l2_ctrl *link_freq; |
2017 | int ret; |
2018 | |
2019 | /* Initialize the subdev. */ |
2020 | v4l2_i2c_subdev_init(sd, client: sensor->client, ops: &mt9m114_ifp_ops); |
2021 | v4l2_i2c_subdev_set_name(sd, client: sensor->client, NULL, postfix: " ifp"); |
2022 | |
2023 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; |
2024 | sd->internal_ops = &mt9m114_ifp_internal_ops; |
2025 | |
2026 | /* Initialize the media entity. */ |
2027 | sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_ISP; |
2028 | sd->entity.ops = &mt9m114_entity_ops; |
2029 | pads[0].flags = MEDIA_PAD_FL_SINK; |
2030 | pads[1].flags = MEDIA_PAD_FL_SOURCE; |
2031 | ret = media_entity_pads_init(entity: &sd->entity, num_pads: 2, pads); |
2032 | if (ret < 0) |
2033 | return ret; |
2034 | |
2035 | sensor->ifp.frame_rate = MT9M114_DEF_FRAME_RATE; |
2036 | |
2037 | /* Initialize the control handler. */ |
2038 | v4l2_ctrl_handler_init(hdl, 8); |
2039 | v4l2_ctrl_new_std(hdl, ops: &mt9m114_ifp_ctrl_ops, |
2040 | V4L2_CID_AUTO_WHITE_BALANCE, |
2041 | min: 0, max: 1, step: 1, def: 1); |
2042 | v4l2_ctrl_new_std_menu(hdl, ops: &mt9m114_ifp_ctrl_ops, |
2043 | V4L2_CID_EXPOSURE_AUTO, |
2044 | max: V4L2_EXPOSURE_MANUAL, mask: 0, |
2045 | def: V4L2_EXPOSURE_AUTO); |
2046 | |
2047 | link_freq = v4l2_ctrl_new_int_menu(hdl, ops: &mt9m114_ifp_ctrl_ops, |
2048 | V4L2_CID_LINK_FREQ, |
2049 | max: sensor->bus_cfg.nr_of_link_frequencies - 1, |
2050 | def: 0, qmenu_int: sensor->bus_cfg.link_frequencies); |
2051 | if (link_freq) |
2052 | link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; |
2053 | |
2054 | v4l2_ctrl_new_std(hdl, ops: &mt9m114_ifp_ctrl_ops, |
2055 | V4L2_CID_PIXEL_RATE, |
2056 | min: sensor->pixrate, max: sensor->pixrate, step: 1, |
2057 | def: sensor->pixrate); |
2058 | |
2059 | sensor->ifp.tpg[MT9M114_TPG_PATTERN] = |
2060 | v4l2_ctrl_new_std_menu_items(hdl, ops: &mt9m114_ifp_ctrl_ops, |
2061 | V4L2_CID_TEST_PATTERN, |
2062 | ARRAY_SIZE(mt9m114_test_pattern_menu) - 1, |
2063 | mask: 0, def: 0, qmenu: mt9m114_test_pattern_menu); |
2064 | sensor->ifp.tpg[MT9M114_TPG_RED] = |
2065 | v4l2_ctrl_new_std(hdl, ops: &mt9m114_ifp_ctrl_ops, |
2066 | V4L2_CID_TEST_PATTERN_RED, |
2067 | min: 0, max: 1023, step: 1, def: 1023); |
2068 | sensor->ifp.tpg[MT9M114_TPG_GREEN] = |
2069 | v4l2_ctrl_new_std(hdl, ops: &mt9m114_ifp_ctrl_ops, |
2070 | V4L2_CID_TEST_PATTERN_GREENR, |
2071 | min: 0, max: 1023, step: 1, def: 1023); |
2072 | sensor->ifp.tpg[MT9M114_TPG_BLUE] = |
2073 | v4l2_ctrl_new_std(hdl, ops: &mt9m114_ifp_ctrl_ops, |
2074 | V4L2_CID_TEST_PATTERN_BLUE, |
2075 | min: 0, max: 1023, step: 1, def: 1023); |
2076 | |
2077 | v4l2_ctrl_cluster(ARRAY_SIZE(sensor->ifp.tpg), controls: sensor->ifp.tpg); |
2078 | |
2079 | if (hdl->error) { |
2080 | ret = hdl->error; |
2081 | goto error; |
2082 | } |
2083 | |
2084 | sd->ctrl_handler = hdl; |
2085 | sd->state_lock = hdl->lock; |
2086 | |
2087 | ret = v4l2_subdev_init_finalize(sd); |
2088 | if (ret) |
2089 | goto error; |
2090 | |
2091 | return 0; |
2092 | |
2093 | error: |
2094 | v4l2_ctrl_handler_free(hdl: &sensor->ifp.hdl); |
2095 | media_entity_cleanup(entity: &sensor->ifp.sd.entity); |
2096 | return ret; |
2097 | } |
2098 | |
2099 | static void mt9m114_ifp_cleanup(struct mt9m114 *sensor) |
2100 | { |
2101 | v4l2_ctrl_handler_free(hdl: &sensor->ifp.hdl); |
2102 | media_entity_cleanup(entity: &sensor->ifp.sd.entity); |
2103 | } |
2104 | |
2105 | /* ----------------------------------------------------------------------------- |
2106 | * Power Management |
2107 | */ |
2108 | |
2109 | static int mt9m114_power_on(struct mt9m114 *sensor) |
2110 | { |
2111 | int ret; |
2112 | |
2113 | /* Enable power and clocks. */ |
2114 | ret = regulator_bulk_enable(ARRAY_SIZE(sensor->supplies), |
2115 | consumers: sensor->supplies); |
2116 | if (ret < 0) |
2117 | return ret; |
2118 | |
2119 | ret = clk_prepare_enable(clk: sensor->clk); |
2120 | if (ret < 0) |
2121 | goto error_regulator; |
2122 | |
2123 | /* Perform a hard reset if available, or a soft reset otherwise. */ |
2124 | if (sensor->reset) { |
2125 | long freq = clk_get_rate(clk: sensor->clk); |
2126 | unsigned int duration; |
2127 | |
2128 | /* |
2129 | * The minimum duration is 50 clock cycles, thus typically |
2130 | * around 2µs. Double it to be safe. |
2131 | */ |
2132 | duration = DIV_ROUND_UP(2 * 50 * 1000000, freq); |
2133 | |
2134 | gpiod_set_value(desc: sensor->reset, value: 1); |
2135 | fsleep(usecs: duration); |
2136 | gpiod_set_value(desc: sensor->reset, value: 0); |
2137 | } else { |
2138 | /* |
2139 | * The power may have just been turned on, we need to wait for |
2140 | * the sensor to be ready to accept I2C commands. |
2141 | */ |
2142 | usleep_range(min: 44500, max: 50000); |
2143 | |
2144 | cci_write(map: sensor->regmap, MT9M114_RESET_AND_MISC_CONTROL, |
2145 | MT9M114_RESET_SOC, err: &ret); |
2146 | cci_write(map: sensor->regmap, MT9M114_RESET_AND_MISC_CONTROL, val: 0, |
2147 | err: &ret); |
2148 | |
2149 | if (ret < 0) { |
2150 | dev_err(&sensor->client->dev, "Soft reset failed\n"); |
2151 | goto error_clock; |
2152 | } |
2153 | } |
2154 | |
2155 | /* |
2156 | * Wait for the sensor to be ready to accept I2C commands by polling the |
2157 | * command register to wait for initialization to complete. |
2158 | */ |
2159 | usleep_range(min: 44500, max: 50000); |
2160 | |
2161 | ret = mt9m114_poll_command(sensor, MT9M114_COMMAND_REGISTER_SET_STATE); |
2162 | if (ret < 0) |
2163 | goto error_clock; |
2164 | |
2165 | if (sensor->bus_cfg.bus_type == V4L2_MBUS_PARALLEL) { |
2166 | /* |
2167 | * In parallel mode (OE set to low), the sensor will enter the |
2168 | * streaming state after initialization. Enter the standby |
2169 | * manually to stop streaming. |
2170 | */ |
2171 | ret = mt9m114_set_state(sensor, |
2172 | MT9M114_SYS_STATE_ENTER_STANDBY); |
2173 | if (ret < 0) |
2174 | goto error_clock; |
2175 | } |
2176 | |
2177 | /* |
2178 | * Before issuing any Set-State command, we must ensure that the sensor |
2179 | * reaches the standby mode (either initiated manually above in |
2180 | * parallel mode, or automatically after reset in MIPI mode). |
2181 | */ |
2182 | ret = mt9m114_poll_state(sensor, MT9M114_SYS_STATE_STANDBY); |
2183 | if (ret < 0) |
2184 | goto error_clock; |
2185 | |
2186 | return 0; |
2187 | |
2188 | error_clock: |
2189 | clk_disable_unprepare(clk: sensor->clk); |
2190 | error_regulator: |
2191 | regulator_bulk_disable(ARRAY_SIZE(sensor->supplies), consumers: sensor->supplies); |
2192 | return ret; |
2193 | } |
2194 | |
2195 | static void mt9m114_power_off(struct mt9m114 *sensor) |
2196 | { |
2197 | clk_disable_unprepare(clk: sensor->clk); |
2198 | regulator_bulk_disable(ARRAY_SIZE(sensor->supplies), consumers: sensor->supplies); |
2199 | } |
2200 | |
2201 | static int __maybe_unused mt9m114_runtime_resume(struct device *dev) |
2202 | { |
2203 | struct v4l2_subdev *sd = dev_get_drvdata(dev); |
2204 | struct mt9m114 *sensor = ifp_to_mt9m114(sd); |
2205 | int ret; |
2206 | |
2207 | ret = mt9m114_power_on(sensor); |
2208 | if (ret) |
2209 | return ret; |
2210 | |
2211 | ret = mt9m114_initialize(sensor); |
2212 | if (ret) { |
2213 | mt9m114_power_off(sensor); |
2214 | return ret; |
2215 | } |
2216 | |
2217 | return 0; |
2218 | } |
2219 | |
2220 | static int __maybe_unused mt9m114_runtime_suspend(struct device *dev) |
2221 | { |
2222 | struct v4l2_subdev *sd = dev_get_drvdata(dev); |
2223 | struct mt9m114 *sensor = ifp_to_mt9m114(sd); |
2224 | |
2225 | mt9m114_power_off(sensor); |
2226 | |
2227 | return 0; |
2228 | } |
2229 | |
2230 | static const struct dev_pm_ops mt9m114_pm_ops = { |
2231 | SET_RUNTIME_PM_OPS(mt9m114_runtime_suspend, mt9m114_runtime_resume, NULL) |
2232 | }; |
2233 | |
2234 | /* ----------------------------------------------------------------------------- |
2235 | * Probe & Remove |
2236 | */ |
2237 | |
2238 | static int mt9m114_clk_init(struct mt9m114 *sensor) |
2239 | { |
2240 | unsigned int link_freq; |
2241 | |
2242 | /* Hardcode the PLL multiplier and dividers to default settings. */ |
2243 | sensor->pll.m = 32; |
2244 | sensor->pll.n = 1; |
2245 | sensor->pll.p = 7; |
2246 | |
2247 | /* |
2248 | * Calculate the pixel rate and link frequency. The CSI-2 bus is clocked |
2249 | * for 16-bit per pixel, transmitted in DDR over a single lane. For |
2250 | * parallel mode, the sensor ouputs one pixel in two PIXCLK cycles. |
2251 | */ |
2252 | sensor->pixrate = clk_get_rate(clk: sensor->clk) * sensor->pll.m |
2253 | / ((sensor->pll.n + 1) * (sensor->pll.p + 1)); |
2254 | |
2255 | link_freq = sensor->bus_cfg.bus_type == V4L2_MBUS_CSI2_DPHY |
2256 | ? sensor->pixrate * 8 : sensor->pixrate * 2; |
2257 | |
2258 | if (sensor->bus_cfg.nr_of_link_frequencies != 1 || |
2259 | sensor->bus_cfg.link_frequencies[0] != link_freq) { |
2260 | dev_err(&sensor->client->dev, "Unsupported DT link-frequencies\n"); |
2261 | return -EINVAL; |
2262 | } |
2263 | |
2264 | return 0; |
2265 | } |
2266 | |
2267 | static int mt9m114_identify(struct mt9m114 *sensor) |
2268 | { |
2269 | u64 major, minor, release, customer; |
2270 | u64 value; |
2271 | int ret; |
2272 | |
2273 | ret = cci_read(map: sensor->regmap, MT9M114_CHIP_ID, val: &value, NULL); |
2274 | if (ret) { |
2275 | dev_err(&sensor->client->dev, "Failed to read chip ID\n"); |
2276 | return -ENXIO; |
2277 | } |
2278 | |
2279 | if (value != 0x2481) { |
2280 | dev_err(&sensor->client->dev, "Invalid chip ID 0x%04llx\n", |
2281 | value); |
2282 | return -ENXIO; |
2283 | } |
2284 | |
2285 | cci_read(map: sensor->regmap, MT9M114_MON_MAJOR_VERSION, val: &major, err: &ret); |
2286 | cci_read(map: sensor->regmap, MT9M114_MON_MINOR_VERSION, val: &minor, err: &ret); |
2287 | cci_read(map: sensor->regmap, MT9M114_MON_RELEASE_VERSION, val: &release, err: &ret); |
2288 | cci_read(map: sensor->regmap, MT9M114_CUSTOMER_REV, val: &customer, err: &ret); |
2289 | if (ret) { |
2290 | dev_err(&sensor->client->dev, "Failed to read version\n"); |
2291 | return -ENXIO; |
2292 | } |
2293 | |
2294 | dev_dbg(&sensor->client->dev, |
2295 | "monitor v%llu.%llu.%04llx customer rev 0x%04llx\n", |
2296 | major, minor, release, customer); |
2297 | |
2298 | return 0; |
2299 | } |
2300 | |
2301 | static int mt9m114_parse_dt(struct mt9m114 *sensor) |
2302 | { |
2303 | struct fwnode_handle *fwnode = dev_fwnode(&sensor->client->dev); |
2304 | struct fwnode_handle *ep; |
2305 | int ret; |
2306 | |
2307 | ep = fwnode_graph_get_next_endpoint(fwnode, NULL); |
2308 | if (!ep) { |
2309 | dev_err(&sensor->client->dev, "No endpoint found\n"); |
2310 | return -EINVAL; |
2311 | } |
2312 | |
2313 | sensor->bus_cfg.bus_type = V4L2_MBUS_UNKNOWN; |
2314 | ret = v4l2_fwnode_endpoint_alloc_parse(fwnode: ep, vep: &sensor->bus_cfg); |
2315 | fwnode_handle_put(fwnode: ep); |
2316 | if (ret < 0) { |
2317 | dev_err(&sensor->client->dev, "Failed to parse endpoint\n"); |
2318 | goto error; |
2319 | } |
2320 | |
2321 | switch (sensor->bus_cfg.bus_type) { |
2322 | case V4L2_MBUS_CSI2_DPHY: |
2323 | case V4L2_MBUS_PARALLEL: |
2324 | break; |
2325 | |
2326 | default: |
2327 | dev_err(&sensor->client->dev, "unsupported bus type %u\n", |
2328 | sensor->bus_cfg.bus_type); |
2329 | ret = -EINVAL; |
2330 | goto error; |
2331 | } |
2332 | |
2333 | return 0; |
2334 | |
2335 | error: |
2336 | v4l2_fwnode_endpoint_free(vep: &sensor->bus_cfg); |
2337 | return ret; |
2338 | } |
2339 | |
2340 | static int mt9m114_probe(struct i2c_client *client) |
2341 | { |
2342 | struct device *dev = &client->dev; |
2343 | struct mt9m114 *sensor; |
2344 | int ret; |
2345 | |
2346 | sensor = devm_kzalloc(dev, size: sizeof(*sensor), GFP_KERNEL); |
2347 | if (!sensor) |
2348 | return -ENOMEM; |
2349 | |
2350 | sensor->client = client; |
2351 | |
2352 | sensor->regmap = devm_cci_regmap_init_i2c(client, reg_addr_bits: 16); |
2353 | if (IS_ERR(ptr: sensor->regmap)) { |
2354 | dev_err(dev, "Unable to initialize I2C\n"); |
2355 | return -ENODEV; |
2356 | } |
2357 | |
2358 | ret = mt9m114_parse_dt(sensor); |
2359 | if (ret < 0) |
2360 | return ret; |
2361 | |
2362 | /* Acquire clocks, GPIOs and regulators. */ |
2363 | sensor->clk = devm_clk_get(dev, NULL); |
2364 | if (IS_ERR(ptr: sensor->clk)) { |
2365 | ret = PTR_ERR(ptr: sensor->clk); |
2366 | dev_err_probe(dev, err: ret, fmt: "Failed to get clock\n"); |
2367 | goto error_ep_free; |
2368 | } |
2369 | |
2370 | sensor->reset = devm_gpiod_get_optional(dev, con_id: "reset", flags: GPIOD_OUT_LOW); |
2371 | if (IS_ERR(ptr: sensor->reset)) { |
2372 | ret = PTR_ERR(ptr: sensor->reset); |
2373 | dev_err_probe(dev, err: ret, fmt: "Failed to get reset GPIO\n"); |
2374 | goto error_ep_free; |
2375 | } |
2376 | |
2377 | sensor->supplies[0].supply = "vddio"; |
2378 | sensor->supplies[1].supply = "vdd"; |
2379 | sensor->supplies[2].supply = "vaa"; |
2380 | |
2381 | ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(sensor->supplies), |
2382 | consumers: sensor->supplies); |
2383 | if (ret < 0) { |
2384 | dev_err_probe(dev, err: ret, fmt: "Failed to get regulators\n"); |
2385 | goto error_ep_free; |
2386 | } |
2387 | |
2388 | ret = mt9m114_clk_init(sensor); |
2389 | if (ret) |
2390 | goto error_ep_free; |
2391 | |
2392 | /* |
2393 | * Identify the sensor. The driver supports runtime PM, but needs to |
2394 | * work when runtime PM is disabled in the kernel. To that end, power |
2395 | * the sensor on manually here, and initialize it after identification |
2396 | * to reach the same state as if resumed through runtime PM. |
2397 | */ |
2398 | ret = mt9m114_power_on(sensor); |
2399 | if (ret < 0) { |
2400 | dev_err_probe(dev, err: ret, fmt: "Could not power on the device\n"); |
2401 | goto error_ep_free; |
2402 | } |
2403 | |
2404 | ret = mt9m114_identify(sensor); |
2405 | if (ret < 0) |
2406 | goto error_power_off; |
2407 | |
2408 | ret = mt9m114_initialize(sensor); |
2409 | if (ret < 0) |
2410 | goto error_power_off; |
2411 | |
2412 | /* |
2413 | * Enable runtime PM with autosuspend. As the device has been powered |
2414 | * manually, mark it as active, and increase the usage count without |
2415 | * resuming the device. |
2416 | */ |
2417 | pm_runtime_set_active(dev); |
2418 | pm_runtime_get_noresume(dev); |
2419 | pm_runtime_enable(dev); |
2420 | pm_runtime_set_autosuspend_delay(dev, delay: 1000); |
2421 | pm_runtime_use_autosuspend(dev); |
2422 | |
2423 | /* Initialize the subdevices. */ |
2424 | ret = mt9m114_pa_init(sensor); |
2425 | if (ret < 0) |
2426 | goto error_pm_cleanup; |
2427 | |
2428 | ret = mt9m114_ifp_init(sensor); |
2429 | if (ret < 0) |
2430 | goto error_pa_cleanup; |
2431 | |
2432 | ret = v4l2_async_register_subdev(sd: &sensor->ifp.sd); |
2433 | if (ret < 0) |
2434 | goto error_ifp_cleanup; |
2435 | |
2436 | /* |
2437 | * Decrease the PM usage count. The device will get suspended after the |
2438 | * autosuspend delay, turning the power off. |
2439 | */ |
2440 | pm_runtime_mark_last_busy(dev); |
2441 | pm_runtime_put_autosuspend(dev); |
2442 | |
2443 | return 0; |
2444 | |
2445 | error_ifp_cleanup: |
2446 | mt9m114_ifp_cleanup(sensor); |
2447 | error_pa_cleanup: |
2448 | mt9m114_pa_cleanup(sensor); |
2449 | error_pm_cleanup: |
2450 | pm_runtime_disable(dev); |
2451 | pm_runtime_put_noidle(dev); |
2452 | error_power_off: |
2453 | mt9m114_power_off(sensor); |
2454 | error_ep_free: |
2455 | v4l2_fwnode_endpoint_free(vep: &sensor->bus_cfg); |
2456 | return ret; |
2457 | } |
2458 | |
2459 | static void mt9m114_remove(struct i2c_client *client) |
2460 | { |
2461 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
2462 | struct mt9m114 *sensor = ifp_to_mt9m114(sd); |
2463 | struct device *dev = &client->dev; |
2464 | |
2465 | v4l2_async_unregister_subdev(sd: &sensor->ifp.sd); |
2466 | |
2467 | mt9m114_ifp_cleanup(sensor); |
2468 | mt9m114_pa_cleanup(sensor); |
2469 | v4l2_fwnode_endpoint_free(vep: &sensor->bus_cfg); |
2470 | |
2471 | /* |
2472 | * Disable runtime PM. In case runtime PM is disabled in the kernel, |
2473 | * make sure to turn power off manually. |
2474 | */ |
2475 | pm_runtime_disable(dev); |
2476 | if (!pm_runtime_status_suspended(dev)) |
2477 | mt9m114_power_off(sensor); |
2478 | pm_runtime_set_suspended(dev); |
2479 | } |
2480 | |
2481 | static const struct of_device_id mt9m114_of_ids[] = { |
2482 | { .compatible = "onnn,mt9m114"}, |
2483 | { /* sentinel */ }, |
2484 | }; |
2485 | MODULE_DEVICE_TABLE(of, mt9m114_of_ids); |
2486 | |
2487 | static struct i2c_driver mt9m114_driver = { |
2488 | .driver = { |
2489 | .name = "mt9m114", |
2490 | .pm = &mt9m114_pm_ops, |
2491 | .of_match_table = mt9m114_of_ids, |
2492 | }, |
2493 | .probe = mt9m114_probe, |
2494 | .remove = mt9m114_remove, |
2495 | }; |
2496 | |
2497 | module_i2c_driver(mt9m114_driver); |
2498 | |
2499 | MODULE_DESCRIPTION("onsemi MT9M114 Sensor Driver"); |
2500 | MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); |
2501 | MODULE_LICENSE("GPL"); |
2502 |
Definitions
- mt9m114_format_flag
- mt9m114_format_info
- mt9m114
- mt9m114_format_infos
- mt9m114_default_format_info
- mt9m114_format_info
- mt9m114_init
- mt9m114_poll_command
- mt9m114_poll_state
- mt9m114_set_state
- mt9m114_initialize
- mt9m114_configure
- mt9m114_set_frame_rate
- mt9m114_start_streaming
- mt9m114_stop_streaming
- mt9m114_entity_ops
- pa_ctrl_to_mt9m114
- mt9m114_pa_g_ctrl
- mt9m114_pa_s_ctrl
- mt9m114_pa_ctrl_ops
- mt9m114_pa_ctrl_update_exposure
- mt9m114_pa_ctrl_update_blanking
- pa_to_mt9m114
- mt9m114_pa_init_state
- mt9m114_pa_enum_mbus_code
- mt9m114_pa_enum_framesizes
- mt9m114_pa_set_fmt
- mt9m114_pa_get_selection
- mt9m114_pa_set_selection
- mt9m114_pa_pad_ops
- mt9m114_pa_ops
- mt9m114_pa_internal_ops
- mt9m114_pa_init
- mt9m114_pa_cleanup
- mt9m114_test_pattern_menu
- mt9m114_test_pattern_value
- ifp_ctrl_to_mt9m114
- mt9m114_ifp_s_ctrl
- mt9m114_ifp_ctrl_ops
- ifp_to_mt9m114
- mt9m114_ifp_s_stream
- mt9m114_ifp_get_frame_interval
- mt9m114_ifp_set_frame_interval
- mt9m114_ifp_init_state
- mt9m114_ifp_enum_mbus_code
- mt9m114_ifp_enum_framesizes
- mt9m114_ifp_enum_frameintervals
- mt9m114_ifp_set_fmt
- mt9m114_ifp_get_selection
- mt9m114_ifp_set_selection
- mt9m114_ifp_unregistered
- mt9m114_ifp_registered
- mt9m114_ifp_video_ops
- mt9m114_ifp_pad_ops
- mt9m114_ifp_ops
- mt9m114_ifp_internal_ops
- mt9m114_ifp_init
- mt9m114_ifp_cleanup
- mt9m114_power_on
- mt9m114_power_off
- mt9m114_runtime_resume
- mt9m114_runtime_suspend
- mt9m114_pm_ops
- mt9m114_clk_init
- mt9m114_identify
- mt9m114_parse_dt
- mt9m114_probe
- mt9m114_remove
- mt9m114_of_ids
Improve your Profiling and Debugging skills
Find out more