Commit | Line | Data |
---|---|---|
c4c0283a BP |
1 | /* |
2 | * Omnivision OV2659 CMOS Image Sensor driver | |
3 | * | |
4 | * Copyright (C) 2015 Texas Instruments, Inc. | |
5 | * | |
6 | * Benoit Parrot <bparrot@ti.com> | |
7 | * Lad, Prabhakar <prabhakar.csengg@gmail.com> | |
8 | * | |
9 | * This program is free software; you may redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License as published by | |
11 | * the Free Software Foundation; version 2 of the License. | |
12 | * | |
13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
14 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
15 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
16 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | |
17 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |
18 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
19 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
20 | * SOFTWARE. | |
21 | */ | |
22 | ||
23 | #include <linux/clk.h> | |
24 | #include <linux/delay.h> | |
25 | #include <linux/err.h> | |
26 | #include <linux/init.h> | |
27 | #include <linux/interrupt.h> | |
28 | #include <linux/io.h> | |
29 | #include <linux/i2c.h> | |
30 | #include <linux/kernel.h> | |
31 | #include <linux/media.h> | |
32 | #include <linux/module.h> | |
33 | #include <linux/of.h> | |
34 | #include <linux/of_graph.h> | |
35 | #include <linux/slab.h> | |
36 | #include <linux/uaccess.h> | |
37 | #include <linux/videodev2.h> | |
38 | ||
39 | #include <media/media-entity.h> | |
40 | #include <media/ov2659.h> | |
41 | #include <media/v4l2-common.h> | |
42 | #include <media/v4l2-ctrls.h> | |
43 | #include <media/v4l2-device.h> | |
44 | #include <media/v4l2-event.h> | |
45 | #include <media/v4l2-image-sizes.h> | |
46 | #include <media/v4l2-mediabus.h> | |
47 | #include <media/v4l2-of.h> | |
48 | #include <media/v4l2-subdev.h> | |
49 | ||
50 | #define DRIVER_NAME "ov2659" | |
51 | ||
52 | /* | |
53 | * OV2659 register definitions | |
54 | */ | |
55 | #define REG_SOFTWARE_STANDBY 0x0100 | |
56 | #define REG_SOFTWARE_RESET 0x0103 | |
57 | #define REG_IO_CTRL00 0x3000 | |
58 | #define REG_IO_CTRL01 0x3001 | |
59 | #define REG_IO_CTRL02 0x3002 | |
60 | #define REG_OUTPUT_VALUE00 0x3008 | |
61 | #define REG_OUTPUT_VALUE01 0x3009 | |
62 | #define REG_OUTPUT_VALUE02 0x300d | |
63 | #define REG_OUTPUT_SELECT00 0x300e | |
64 | #define REG_OUTPUT_SELECT01 0x300f | |
65 | #define REG_OUTPUT_SELECT02 0x3010 | |
66 | #define REG_OUTPUT_DRIVE 0x3011 | |
67 | #define REG_INPUT_READOUT00 0x302d | |
68 | #define REG_INPUT_READOUT01 0x302e | |
69 | #define REG_INPUT_READOUT02 0x302f | |
70 | ||
71 | #define REG_SC_PLL_CTRL0 0x3003 | |
72 | #define REG_SC_PLL_CTRL1 0x3004 | |
73 | #define REG_SC_PLL_CTRL2 0x3005 | |
74 | #define REG_SC_PLL_CTRL3 0x3006 | |
75 | #define REG_SC_CHIP_ID_H 0x300a | |
76 | #define REG_SC_CHIP_ID_L 0x300b | |
77 | #define REG_SC_PWC 0x3014 | |
78 | #define REG_SC_CLKRST0 0x301a | |
79 | #define REG_SC_CLKRST1 0x301b | |
80 | #define REG_SC_CLKRST2 0x301c | |
81 | #define REG_SC_CLKRST3 0x301d | |
82 | #define REG_SC_SUB_ID 0x302a | |
83 | #define REG_SC_SCCB_ID 0x302b | |
84 | ||
85 | #define REG_GROUP_ADDRESS_00 0x3200 | |
86 | #define REG_GROUP_ADDRESS_01 0x3201 | |
87 | #define REG_GROUP_ADDRESS_02 0x3202 | |
88 | #define REG_GROUP_ADDRESS_03 0x3203 | |
89 | #define REG_GROUP_ACCESS 0x3208 | |
90 | ||
91 | #define REG_AWB_R_GAIN_H 0x3400 | |
92 | #define REG_AWB_R_GAIN_L 0x3401 | |
93 | #define REG_AWB_G_GAIN_H 0x3402 | |
94 | #define REG_AWB_G_GAIN_L 0x3403 | |
95 | #define REG_AWB_B_GAIN_H 0x3404 | |
96 | #define REG_AWB_B_GAIN_L 0x3405 | |
97 | #define REG_AWB_MANUAL_CONTROL 0x3406 | |
98 | ||
99 | #define REG_TIMING_HS_H 0x3800 | |
100 | #define REG_TIMING_HS_L 0x3801 | |
101 | #define REG_TIMING_VS_H 0x3802 | |
102 | #define REG_TIMING_VS_L 0x3803 | |
103 | #define REG_TIMING_HW_H 0x3804 | |
104 | #define REG_TIMING_HW_L 0x3805 | |
105 | #define REG_TIMING_VH_H 0x3806 | |
106 | #define REG_TIMING_VH_L 0x3807 | |
107 | #define REG_TIMING_DVPHO_H 0x3808 | |
108 | #define REG_TIMING_DVPHO_L 0x3809 | |
109 | #define REG_TIMING_DVPVO_H 0x380a | |
110 | #define REG_TIMING_DVPVO_L 0x380b | |
111 | #define REG_TIMING_HTS_H 0x380c | |
112 | #define REG_TIMING_HTS_L 0x380d | |
113 | #define REG_TIMING_VTS_H 0x380e | |
114 | #define REG_TIMING_VTS_L 0x380f | |
115 | #define REG_TIMING_HOFFS_H 0x3810 | |
116 | #define REG_TIMING_HOFFS_L 0x3811 | |
117 | #define REG_TIMING_VOFFS_H 0x3812 | |
118 | #define REG_TIMING_VOFFS_L 0x3813 | |
119 | #define REG_TIMING_XINC 0x3814 | |
120 | #define REG_TIMING_YINC 0x3815 | |
121 | #define REG_TIMING_VERT_FORMAT 0x3820 | |
122 | #define REG_TIMING_HORIZ_FORMAT 0x3821 | |
123 | ||
124 | #define REG_FORMAT_CTRL00 0x4300 | |
125 | ||
126 | #define REG_VFIFO_READ_START_H 0x4608 | |
127 | #define REG_VFIFO_READ_START_L 0x4609 | |
128 | ||
129 | #define REG_DVP_CTRL02 0x4708 | |
130 | ||
131 | #define REG_ISP_CTRL00 0x5000 | |
132 | #define REG_ISP_CTRL01 0x5001 | |
133 | #define REG_ISP_CTRL02 0x5002 | |
134 | ||
135 | #define REG_LENC_RED_X0_H 0x500c | |
136 | #define REG_LENC_RED_X0_L 0x500d | |
137 | #define REG_LENC_RED_Y0_H 0x500e | |
138 | #define REG_LENC_RED_Y0_L 0x500f | |
139 | #define REG_LENC_RED_A1 0x5010 | |
140 | #define REG_LENC_RED_B1 0x5011 | |
141 | #define REG_LENC_RED_A2_B2 0x5012 | |
142 | #define REG_LENC_GREEN_X0_H 0x5013 | |
143 | #define REG_LENC_GREEN_X0_L 0x5014 | |
144 | #define REG_LENC_GREEN_Y0_H 0x5015 | |
145 | #define REG_LENC_GREEN_Y0_L 0x5016 | |
146 | #define REG_LENC_GREEN_A1 0x5017 | |
147 | #define REG_LENC_GREEN_B1 0x5018 | |
148 | #define REG_LENC_GREEN_A2_B2 0x5019 | |
149 | #define REG_LENC_BLUE_X0_H 0x501a | |
150 | #define REG_LENC_BLUE_X0_L 0x501b | |
151 | #define REG_LENC_BLUE_Y0_H 0x501c | |
152 | #define REG_LENC_BLUE_Y0_L 0x501d | |
153 | #define REG_LENC_BLUE_A1 0x501e | |
154 | #define REG_LENC_BLUE_B1 0x501f | |
155 | #define REG_LENC_BLUE_A2_B2 0x5020 | |
156 | ||
157 | #define REG_AWB_CTRL00 0x5035 | |
158 | #define REG_AWB_CTRL01 0x5036 | |
159 | #define REG_AWB_CTRL02 0x5037 | |
160 | #define REG_AWB_CTRL03 0x5038 | |
161 | #define REG_AWB_CTRL04 0x5039 | |
162 | #define REG_AWB_LOCAL_LIMIT 0x503a | |
163 | #define REG_AWB_CTRL12 0x5049 | |
164 | #define REG_AWB_CTRL13 0x504a | |
165 | #define REG_AWB_CTRL14 0x504b | |
166 | ||
167 | #define REG_SHARPENMT_THRESH1 0x5064 | |
168 | #define REG_SHARPENMT_THRESH2 0x5065 | |
169 | #define REG_SHARPENMT_OFFSET1 0x5066 | |
170 | #define REG_SHARPENMT_OFFSET2 0x5067 | |
171 | #define REG_DENOISE_THRESH1 0x5068 | |
172 | #define REG_DENOISE_THRESH2 0x5069 | |
173 | #define REG_DENOISE_OFFSET1 0x506a | |
174 | #define REG_DENOISE_OFFSET2 0x506b | |
175 | #define REG_SHARPEN_THRESH1 0x506c | |
176 | #define REG_SHARPEN_THRESH2 0x506d | |
177 | #define REG_CIP_CTRL00 0x506e | |
178 | #define REG_CIP_CTRL01 0x506f | |
179 | ||
180 | #define REG_CMX_SIGN 0x5079 | |
181 | #define REG_CMX_MISC_CTRL 0x507a | |
182 | ||
183 | #define REG_PRE_ISP_CTRL00 0x50a0 | |
184 | #define TEST_PATTERN_ENABLE BIT(7) | |
185 | #define VERTICAL_COLOR_BAR_MASK 0x53 | |
186 | ||
187 | #define REG_NULL 0x0000 /* Array end token */ | |
188 | ||
189 | #define OV265X_ID(_msb, _lsb) ((_msb) << 8 | (_lsb)) | |
190 | #define OV2659_ID 0x2656 | |
191 | ||
192 | struct sensor_register { | |
193 | u16 addr; | |
194 | u8 value; | |
195 | }; | |
196 | ||
197 | struct ov2659_framesize { | |
198 | u16 width; | |
199 | u16 height; | |
200 | u16 max_exp_lines; | |
201 | const struct sensor_register *regs; | |
202 | }; | |
203 | ||
204 | struct ov2659_pll_ctrl { | |
205 | u8 ctrl1; | |
206 | u8 ctrl2; | |
207 | u8 ctrl3; | |
208 | }; | |
209 | ||
210 | struct ov2659_pixfmt { | |
211 | u32 code; | |
212 | /* Output format Register Value (REG_FORMAT_CTRL00) */ | |
213 | struct sensor_register *format_ctrl_regs; | |
214 | }; | |
215 | ||
216 | struct pll_ctrl_reg { | |
217 | unsigned int div; | |
218 | unsigned char reg; | |
219 | }; | |
220 | ||
221 | struct ov2659 { | |
222 | struct v4l2_subdev sd; | |
223 | struct media_pad pad; | |
224 | struct v4l2_mbus_framefmt format; | |
225 | unsigned int xvclk_frequency; | |
226 | const struct ov2659_platform_data *pdata; | |
227 | struct mutex lock; | |
228 | struct i2c_client *client; | |
229 | struct v4l2_ctrl_handler ctrls; | |
230 | struct v4l2_ctrl *link_frequency; | |
231 | const struct ov2659_framesize *frame_size; | |
232 | struct sensor_register *format_ctrl_regs; | |
233 | struct ov2659_pll_ctrl pll; | |
234 | int streaming; | |
235 | }; | |
236 | ||
237 | static const struct sensor_register ov2659_init_regs[] = { | |
238 | { REG_IO_CTRL00, 0x03 }, | |
239 | { REG_IO_CTRL01, 0xff }, | |
240 | { REG_IO_CTRL02, 0xe0 }, | |
241 | { 0x3633, 0x3d }, | |
242 | { 0x3620, 0x02 }, | |
243 | { 0x3631, 0x11 }, | |
244 | { 0x3612, 0x04 }, | |
245 | { 0x3630, 0x20 }, | |
246 | { 0x4702, 0x02 }, | |
247 | { 0x370c, 0x34 }, | |
248 | { REG_TIMING_HS_H, 0x00 }, | |
249 | { REG_TIMING_HS_L, 0x00 }, | |
250 | { REG_TIMING_VS_H, 0x00 }, | |
251 | { REG_TIMING_VS_L, 0x00 }, | |
252 | { REG_TIMING_HW_H, 0x06 }, | |
253 | { REG_TIMING_HW_L, 0x5f }, | |
254 | { REG_TIMING_VH_H, 0x04 }, | |
255 | { REG_TIMING_VH_L, 0xb7 }, | |
256 | { REG_TIMING_DVPHO_H, 0x03 }, | |
257 | { REG_TIMING_DVPHO_L, 0x20 }, | |
258 | { REG_TIMING_DVPVO_H, 0x02 }, | |
259 | { REG_TIMING_DVPVO_L, 0x58 }, | |
260 | { REG_TIMING_HTS_H, 0x05 }, | |
261 | { REG_TIMING_HTS_L, 0x14 }, | |
262 | { REG_TIMING_VTS_H, 0x02 }, | |
263 | { REG_TIMING_VTS_L, 0x68 }, | |
264 | { REG_TIMING_HOFFS_L, 0x08 }, | |
265 | { REG_TIMING_VOFFS_L, 0x02 }, | |
266 | { REG_TIMING_XINC, 0x31 }, | |
267 | { REG_TIMING_YINC, 0x31 }, | |
268 | { 0x3a02, 0x02 }, | |
269 | { 0x3a03, 0x68 }, | |
270 | { 0x3a08, 0x00 }, | |
271 | { 0x3a09, 0x5c }, | |
272 | { 0x3a0a, 0x00 }, | |
273 | { 0x3a0b, 0x4d }, | |
274 | { 0x3a0d, 0x08 }, | |
275 | { 0x3a0e, 0x06 }, | |
276 | { 0x3a14, 0x02 }, | |
277 | { 0x3a15, 0x28 }, | |
278 | { REG_DVP_CTRL02, 0x01 }, | |
279 | { 0x3623, 0x00 }, | |
280 | { 0x3634, 0x76 }, | |
281 | { 0x3701, 0x44 }, | |
282 | { 0x3702, 0x18 }, | |
283 | { 0x3703, 0x24 }, | |
284 | { 0x3704, 0x24 }, | |
285 | { 0x3705, 0x0c }, | |
286 | { REG_TIMING_VERT_FORMAT, 0x81 }, | |
287 | { REG_TIMING_HORIZ_FORMAT, 0x01 }, | |
288 | { 0x370a, 0x52 }, | |
289 | { REG_VFIFO_READ_START_H, 0x00 }, | |
290 | { REG_VFIFO_READ_START_L, 0x80 }, | |
291 | { REG_FORMAT_CTRL00, 0x30 }, | |
292 | { 0x5086, 0x02 }, | |
293 | { REG_ISP_CTRL00, 0xfb }, | |
294 | { REG_ISP_CTRL01, 0x1f }, | |
295 | { REG_ISP_CTRL02, 0x00 }, | |
296 | { 0x5025, 0x0e }, | |
297 | { 0x5026, 0x18 }, | |
298 | { 0x5027, 0x34 }, | |
299 | { 0x5028, 0x4c }, | |
300 | { 0x5029, 0x62 }, | |
301 | { 0x502a, 0x74 }, | |
302 | { 0x502b, 0x85 }, | |
303 | { 0x502c, 0x92 }, | |
304 | { 0x502d, 0x9e }, | |
305 | { 0x502e, 0xb2 }, | |
306 | { 0x502f, 0xc0 }, | |
307 | { 0x5030, 0xcc }, | |
308 | { 0x5031, 0xe0 }, | |
309 | { 0x5032, 0xee }, | |
310 | { 0x5033, 0xf6 }, | |
311 | { 0x5034, 0x11 }, | |
312 | { 0x5070, 0x1c }, | |
313 | { 0x5071, 0x5b }, | |
314 | { 0x5072, 0x05 }, | |
315 | { 0x5073, 0x20 }, | |
316 | { 0x5074, 0x94 }, | |
317 | { 0x5075, 0xb4 }, | |
318 | { 0x5076, 0xb4 }, | |
319 | { 0x5077, 0xaf }, | |
320 | { 0x5078, 0x05 }, | |
321 | { REG_CMX_SIGN, 0x98 }, | |
322 | { REG_CMX_MISC_CTRL, 0x21 }, | |
323 | { REG_AWB_CTRL00, 0x6a }, | |
324 | { REG_AWB_CTRL01, 0x11 }, | |
325 | { REG_AWB_CTRL02, 0x92 }, | |
326 | { REG_AWB_CTRL03, 0x21 }, | |
327 | { REG_AWB_CTRL04, 0xe1 }, | |
328 | { REG_AWB_LOCAL_LIMIT, 0x01 }, | |
329 | { 0x503c, 0x05 }, | |
330 | { 0x503d, 0x08 }, | |
331 | { 0x503e, 0x08 }, | |
332 | { 0x503f, 0x64 }, | |
333 | { 0x5040, 0x58 }, | |
334 | { 0x5041, 0x2a }, | |
335 | { 0x5042, 0xc5 }, | |
336 | { 0x5043, 0x2e }, | |
337 | { 0x5044, 0x3a }, | |
338 | { 0x5045, 0x3c }, | |
339 | { 0x5046, 0x44 }, | |
340 | { 0x5047, 0xf8 }, | |
341 | { 0x5048, 0x08 }, | |
342 | { REG_AWB_CTRL12, 0x70 }, | |
343 | { REG_AWB_CTRL13, 0xf0 }, | |
344 | { REG_AWB_CTRL14, 0xf0 }, | |
345 | { REG_LENC_RED_X0_H, 0x03 }, | |
346 | { REG_LENC_RED_X0_L, 0x20 }, | |
347 | { REG_LENC_RED_Y0_H, 0x02 }, | |
348 | { REG_LENC_RED_Y0_L, 0x5c }, | |
349 | { REG_LENC_RED_A1, 0x48 }, | |
350 | { REG_LENC_RED_B1, 0x00 }, | |
351 | { REG_LENC_RED_A2_B2, 0x66 }, | |
352 | { REG_LENC_GREEN_X0_H, 0x03 }, | |
353 | { REG_LENC_GREEN_X0_L, 0x30 }, | |
354 | { REG_LENC_GREEN_Y0_H, 0x02 }, | |
355 | { REG_LENC_GREEN_Y0_L, 0x7c }, | |
356 | { REG_LENC_GREEN_A1, 0x40 }, | |
357 | { REG_LENC_GREEN_B1, 0x00 }, | |
358 | { REG_LENC_GREEN_A2_B2, 0x66 }, | |
359 | { REG_LENC_BLUE_X0_H, 0x03 }, | |
360 | { REG_LENC_BLUE_X0_L, 0x10 }, | |
361 | { REG_LENC_BLUE_Y0_H, 0x02 }, | |
362 | { REG_LENC_BLUE_Y0_L, 0x7c }, | |
363 | { REG_LENC_BLUE_A1, 0x3a }, | |
364 | { REG_LENC_BLUE_B1, 0x00 }, | |
365 | { REG_LENC_BLUE_A2_B2, 0x66 }, | |
366 | { REG_CIP_CTRL00, 0x44 }, | |
367 | { REG_SHARPENMT_THRESH1, 0x08 }, | |
368 | { REG_SHARPENMT_THRESH2, 0x10 }, | |
369 | { REG_SHARPENMT_OFFSET1, 0x12 }, | |
370 | { REG_SHARPENMT_OFFSET2, 0x02 }, | |
371 | { REG_SHARPEN_THRESH1, 0x08 }, | |
372 | { REG_SHARPEN_THRESH2, 0x10 }, | |
373 | { REG_CIP_CTRL01, 0xa6 }, | |
374 | { REG_DENOISE_THRESH1, 0x08 }, | |
375 | { REG_DENOISE_THRESH2, 0x10 }, | |
376 | { REG_DENOISE_OFFSET1, 0x04 }, | |
377 | { REG_DENOISE_OFFSET2, 0x12 }, | |
378 | { 0x507e, 0x40 }, | |
379 | { 0x507f, 0x20 }, | |
380 | { 0x507b, 0x02 }, | |
381 | { REG_CMX_MISC_CTRL, 0x01 }, | |
382 | { 0x5084, 0x0c }, | |
383 | { 0x5085, 0x3e }, | |
384 | { 0x5005, 0x80 }, | |
385 | { 0x3a0f, 0x30 }, | |
386 | { 0x3a10, 0x28 }, | |
387 | { 0x3a1b, 0x32 }, | |
388 | { 0x3a1e, 0x26 }, | |
389 | { 0x3a11, 0x60 }, | |
390 | { 0x3a1f, 0x14 }, | |
391 | { 0x5060, 0x69 }, | |
392 | { 0x5061, 0x7d }, | |
393 | { 0x5062, 0x7d }, | |
394 | { 0x5063, 0x69 }, | |
395 | { REG_NULL, 0x00 }, | |
396 | }; | |
397 | ||
398 | /* 1280X720 720p */ | |
399 | static struct sensor_register ov2659_720p[] = { | |
400 | { REG_TIMING_HS_H, 0x00 }, | |
401 | { REG_TIMING_HS_L, 0xa0 }, | |
402 | { REG_TIMING_VS_H, 0x00 }, | |
403 | { REG_TIMING_VS_L, 0xf0 }, | |
404 | { REG_TIMING_HW_H, 0x05 }, | |
405 | { REG_TIMING_HW_L, 0xbf }, | |
406 | { REG_TIMING_VH_H, 0x03 }, | |
407 | { REG_TIMING_VH_L, 0xcb }, | |
408 | { REG_TIMING_DVPHO_H, 0x05 }, | |
409 | { REG_TIMING_DVPHO_L, 0x00 }, | |
410 | { REG_TIMING_DVPVO_H, 0x02 }, | |
411 | { REG_TIMING_DVPVO_L, 0xd0 }, | |
412 | { REG_TIMING_HTS_H, 0x06 }, | |
413 | { REG_TIMING_HTS_L, 0x4c }, | |
414 | { REG_TIMING_VTS_H, 0x02 }, | |
415 | { REG_TIMING_VTS_L, 0xe8 }, | |
416 | { REG_TIMING_HOFFS_L, 0x10 }, | |
417 | { REG_TIMING_VOFFS_L, 0x06 }, | |
418 | { REG_TIMING_XINC, 0x11 }, | |
419 | { REG_TIMING_YINC, 0x11 }, | |
420 | { REG_TIMING_VERT_FORMAT, 0x80 }, | |
421 | { REG_TIMING_HORIZ_FORMAT, 0x00 }, | |
422 | { 0x3a03, 0xe8 }, | |
423 | { 0x3a09, 0x6f }, | |
424 | { 0x3a0b, 0x5d }, | |
425 | { 0x3a15, 0x9a }, | |
426 | { REG_NULL, 0x00 }, | |
427 | }; | |
428 | ||
429 | /* 1600X1200 UXGA */ | |
430 | static struct sensor_register ov2659_uxga[] = { | |
431 | { REG_TIMING_HS_H, 0x00 }, | |
432 | { REG_TIMING_HS_L, 0x00 }, | |
433 | { REG_TIMING_VS_H, 0x00 }, | |
434 | { REG_TIMING_VS_L, 0x00 }, | |
435 | { REG_TIMING_HW_H, 0x06 }, | |
436 | { REG_TIMING_HW_L, 0x5f }, | |
437 | { REG_TIMING_VH_H, 0x04 }, | |
438 | { REG_TIMING_VH_L, 0xbb }, | |
439 | { REG_TIMING_DVPHO_H, 0x06 }, | |
440 | { REG_TIMING_DVPHO_L, 0x40 }, | |
441 | { REG_TIMING_DVPVO_H, 0x04 }, | |
442 | { REG_TIMING_DVPVO_L, 0xb0 }, | |
443 | { REG_TIMING_HTS_H, 0x07 }, | |
444 | { REG_TIMING_HTS_L, 0x9f }, | |
445 | { REG_TIMING_VTS_H, 0x04 }, | |
446 | { REG_TIMING_VTS_L, 0xd0 }, | |
447 | { REG_TIMING_HOFFS_L, 0x10 }, | |
448 | { REG_TIMING_VOFFS_L, 0x06 }, | |
449 | { REG_TIMING_XINC, 0x11 }, | |
450 | { REG_TIMING_YINC, 0x11 }, | |
451 | { 0x3a02, 0x04 }, | |
452 | { 0x3a03, 0xd0 }, | |
453 | { 0x3a08, 0x00 }, | |
454 | { 0x3a09, 0xb8 }, | |
455 | { 0x3a0a, 0x00 }, | |
456 | { 0x3a0b, 0x9a }, | |
457 | { 0x3a0d, 0x08 }, | |
458 | { 0x3a0e, 0x06 }, | |
459 | { 0x3a14, 0x04 }, | |
460 | { 0x3a15, 0x50 }, | |
461 | { 0x3623, 0x00 }, | |
462 | { 0x3634, 0x44 }, | |
463 | { 0x3701, 0x44 }, | |
464 | { 0x3702, 0x30 }, | |
465 | { 0x3703, 0x48 }, | |
466 | { 0x3704, 0x48 }, | |
467 | { 0x3705, 0x18 }, | |
468 | { REG_TIMING_VERT_FORMAT, 0x80 }, | |
469 | { REG_TIMING_HORIZ_FORMAT, 0x00 }, | |
470 | { 0x370a, 0x12 }, | |
471 | { REG_VFIFO_READ_START_H, 0x00 }, | |
472 | { REG_VFIFO_READ_START_L, 0x80 }, | |
473 | { REG_ISP_CTRL02, 0x00 }, | |
474 | { REG_NULL, 0x00 }, | |
475 | }; | |
476 | ||
477 | /* 1280X1024 SXGA */ | |
478 | static struct sensor_register ov2659_sxga[] = { | |
479 | { REG_TIMING_HS_H, 0x00 }, | |
480 | { REG_TIMING_HS_L, 0x00 }, | |
481 | { REG_TIMING_VS_H, 0x00 }, | |
482 | { REG_TIMING_VS_L, 0x00 }, | |
483 | { REG_TIMING_HW_H, 0x06 }, | |
484 | { REG_TIMING_HW_L, 0x5f }, | |
485 | { REG_TIMING_VH_H, 0x04 }, | |
486 | { REG_TIMING_VH_L, 0xb7 }, | |
487 | { REG_TIMING_DVPHO_H, 0x05 }, | |
488 | { REG_TIMING_DVPHO_L, 0x00 }, | |
489 | { REG_TIMING_DVPVO_H, 0x04 }, | |
490 | { REG_TIMING_DVPVO_L, 0x00 }, | |
491 | { REG_TIMING_HTS_H, 0x07 }, | |
492 | { REG_TIMING_HTS_L, 0x9c }, | |
493 | { REG_TIMING_VTS_H, 0x04 }, | |
494 | { REG_TIMING_VTS_L, 0xd0 }, | |
495 | { REG_TIMING_HOFFS_L, 0x10 }, | |
496 | { REG_TIMING_VOFFS_L, 0x06 }, | |
497 | { REG_TIMING_XINC, 0x11 }, | |
498 | { REG_TIMING_YINC, 0x11 }, | |
499 | { 0x3a02, 0x02 }, | |
500 | { 0x3a03, 0x68 }, | |
501 | { 0x3a08, 0x00 }, | |
502 | { 0x3a09, 0x5c }, | |
503 | { 0x3a0a, 0x00 }, | |
504 | { 0x3a0b, 0x4d }, | |
505 | { 0x3a0d, 0x08 }, | |
506 | { 0x3a0e, 0x06 }, | |
507 | { 0x3a14, 0x02 }, | |
508 | { 0x3a15, 0x28 }, | |
509 | { 0x3623, 0x00 }, | |
510 | { 0x3634, 0x76 }, | |
511 | { 0x3701, 0x44 }, | |
512 | { 0x3702, 0x18 }, | |
513 | { 0x3703, 0x24 }, | |
514 | { 0x3704, 0x24 }, | |
515 | { 0x3705, 0x0c }, | |
516 | { REG_TIMING_VERT_FORMAT, 0x80 }, | |
517 | { REG_TIMING_HORIZ_FORMAT, 0x00 }, | |
518 | { 0x370a, 0x52 }, | |
519 | { REG_VFIFO_READ_START_H, 0x00 }, | |
520 | { REG_VFIFO_READ_START_L, 0x80 }, | |
521 | { REG_ISP_CTRL02, 0x00 }, | |
522 | { REG_NULL, 0x00 }, | |
523 | }; | |
524 | ||
525 | /* 1024X768 SXGA */ | |
526 | static struct sensor_register ov2659_xga[] = { | |
527 | { REG_TIMING_HS_H, 0x00 }, | |
528 | { REG_TIMING_HS_L, 0x00 }, | |
529 | { REG_TIMING_VS_H, 0x00 }, | |
530 | { REG_TIMING_VS_L, 0x00 }, | |
531 | { REG_TIMING_HW_H, 0x06 }, | |
532 | { REG_TIMING_HW_L, 0x5f }, | |
533 | { REG_TIMING_VH_H, 0x04 }, | |
534 | { REG_TIMING_VH_L, 0xb7 }, | |
535 | { REG_TIMING_DVPHO_H, 0x04 }, | |
536 | { REG_TIMING_DVPHO_L, 0x00 }, | |
537 | { REG_TIMING_DVPVO_H, 0x03 }, | |
538 | { REG_TIMING_DVPVO_L, 0x00 }, | |
539 | { REG_TIMING_HTS_H, 0x07 }, | |
540 | { REG_TIMING_HTS_L, 0x9c }, | |
541 | { REG_TIMING_VTS_H, 0x04 }, | |
542 | { REG_TIMING_VTS_L, 0xd0 }, | |
543 | { REG_TIMING_HOFFS_L, 0x10 }, | |
544 | { REG_TIMING_VOFFS_L, 0x06 }, | |
545 | { REG_TIMING_XINC, 0x11 }, | |
546 | { REG_TIMING_YINC, 0x11 }, | |
547 | { 0x3a02, 0x02 }, | |
548 | { 0x3a03, 0x68 }, | |
549 | { 0x3a08, 0x00 }, | |
550 | { 0x3a09, 0x5c }, | |
551 | { 0x3a0a, 0x00 }, | |
552 | { 0x3a0b, 0x4d }, | |
553 | { 0x3a0d, 0x08 }, | |
554 | { 0x3a0e, 0x06 }, | |
555 | { 0x3a14, 0x02 }, | |
556 | { 0x3a15, 0x28 }, | |
557 | { 0x3623, 0x00 }, | |
558 | { 0x3634, 0x76 }, | |
559 | { 0x3701, 0x44 }, | |
560 | { 0x3702, 0x18 }, | |
561 | { 0x3703, 0x24 }, | |
562 | { 0x3704, 0x24 }, | |
563 | { 0x3705, 0x0c }, | |
564 | { REG_TIMING_VERT_FORMAT, 0x80 }, | |
565 | { REG_TIMING_HORIZ_FORMAT, 0x00 }, | |
566 | { 0x370a, 0x52 }, | |
567 | { REG_VFIFO_READ_START_H, 0x00 }, | |
568 | { REG_VFIFO_READ_START_L, 0x80 }, | |
569 | { REG_ISP_CTRL02, 0x00 }, | |
570 | { REG_NULL, 0x00 }, | |
571 | }; | |
572 | ||
573 | /* 800X600 SVGA */ | |
574 | static struct sensor_register ov2659_svga[] = { | |
575 | { REG_TIMING_HS_H, 0x00 }, | |
576 | { REG_TIMING_HS_L, 0x00 }, | |
577 | { REG_TIMING_VS_H, 0x00 }, | |
578 | { REG_TIMING_VS_L, 0x00 }, | |
579 | { REG_TIMING_HW_H, 0x06 }, | |
580 | { REG_TIMING_HW_L, 0x5f }, | |
581 | { REG_TIMING_VH_H, 0x04 }, | |
582 | { REG_TIMING_VH_L, 0xb7 }, | |
583 | { REG_TIMING_DVPHO_H, 0x03 }, | |
584 | { REG_TIMING_DVPHO_L, 0x20 }, | |
585 | { REG_TIMING_DVPVO_H, 0x02 }, | |
586 | { REG_TIMING_DVPVO_L, 0x58 }, | |
587 | { REG_TIMING_HTS_H, 0x05 }, | |
588 | { REG_TIMING_HTS_L, 0x14 }, | |
589 | { REG_TIMING_VTS_H, 0x02 }, | |
590 | { REG_TIMING_VTS_L, 0x68 }, | |
591 | { REG_TIMING_HOFFS_L, 0x08 }, | |
592 | { REG_TIMING_VOFFS_L, 0x02 }, | |
593 | { REG_TIMING_XINC, 0x31 }, | |
594 | { REG_TIMING_YINC, 0x31 }, | |
595 | { 0x3a02, 0x02 }, | |
596 | { 0x3a03, 0x68 }, | |
597 | { 0x3a08, 0x00 }, | |
598 | { 0x3a09, 0x5c }, | |
599 | { 0x3a0a, 0x00 }, | |
600 | { 0x3a0b, 0x4d }, | |
601 | { 0x3a0d, 0x08 }, | |
602 | { 0x3a0e, 0x06 }, | |
603 | { 0x3a14, 0x02 }, | |
604 | { 0x3a15, 0x28 }, | |
605 | { 0x3623, 0x00 }, | |
606 | { 0x3634, 0x76 }, | |
607 | { 0x3701, 0x44 }, | |
608 | { 0x3702, 0x18 }, | |
609 | { 0x3703, 0x24 }, | |
610 | { 0x3704, 0x24 }, | |
611 | { 0x3705, 0x0c }, | |
612 | { REG_TIMING_VERT_FORMAT, 0x81 }, | |
613 | { REG_TIMING_HORIZ_FORMAT, 0x01 }, | |
614 | { 0x370a, 0x52 }, | |
615 | { REG_VFIFO_READ_START_H, 0x00 }, | |
616 | { REG_VFIFO_READ_START_L, 0x80 }, | |
617 | { REG_ISP_CTRL02, 0x00 }, | |
618 | { REG_NULL, 0x00 }, | |
619 | }; | |
620 | ||
621 | /* 640X480 VGA */ | |
622 | static struct sensor_register ov2659_vga[] = { | |
623 | { REG_TIMING_HS_H, 0x00 }, | |
624 | { REG_TIMING_HS_L, 0x00 }, | |
625 | { REG_TIMING_VS_H, 0x00 }, | |
626 | { REG_TIMING_VS_L, 0x00 }, | |
627 | { REG_TIMING_HW_H, 0x06 }, | |
628 | { REG_TIMING_HW_L, 0x5f }, | |
629 | { REG_TIMING_VH_H, 0x04 }, | |
630 | { REG_TIMING_VH_L, 0xb7 }, | |
631 | { REG_TIMING_DVPHO_H, 0x02 }, | |
632 | { REG_TIMING_DVPHO_L, 0x80 }, | |
633 | { REG_TIMING_DVPVO_H, 0x01 }, | |
634 | { REG_TIMING_DVPVO_L, 0xe0 }, | |
635 | { REG_TIMING_HTS_H, 0x05 }, | |
636 | { REG_TIMING_HTS_L, 0x14 }, | |
637 | { REG_TIMING_VTS_H, 0x02 }, | |
638 | { REG_TIMING_VTS_L, 0x68 }, | |
639 | { REG_TIMING_HOFFS_L, 0x08 }, | |
640 | { REG_TIMING_VOFFS_L, 0x02 }, | |
641 | { REG_TIMING_XINC, 0x31 }, | |
642 | { REG_TIMING_YINC, 0x31 }, | |
643 | { 0x3a02, 0x02 }, | |
644 | { 0x3a03, 0x68 }, | |
645 | { 0x3a08, 0x00 }, | |
646 | { 0x3a09, 0x5c }, | |
647 | { 0x3a0a, 0x00 }, | |
648 | { 0x3a0b, 0x4d }, | |
649 | { 0x3a0d, 0x08 }, | |
650 | { 0x3a0e, 0x06 }, | |
651 | { 0x3a14, 0x02 }, | |
652 | { 0x3a15, 0x28 }, | |
653 | { 0x3623, 0x00 }, | |
654 | { 0x3634, 0x76 }, | |
655 | { 0x3701, 0x44 }, | |
656 | { 0x3702, 0x18 }, | |
657 | { 0x3703, 0x24 }, | |
658 | { 0x3704, 0x24 }, | |
659 | { 0x3705, 0x0c }, | |
660 | { REG_TIMING_VERT_FORMAT, 0x81 }, | |
661 | { REG_TIMING_HORIZ_FORMAT, 0x01 }, | |
662 | { 0x370a, 0x52 }, | |
663 | { REG_VFIFO_READ_START_H, 0x00 }, | |
664 | { REG_VFIFO_READ_START_L, 0x80 }, | |
665 | { REG_ISP_CTRL02, 0x10 }, | |
666 | { REG_NULL, 0x00 }, | |
667 | }; | |
668 | ||
669 | /* 320X240 QVGA */ | |
670 | static struct sensor_register ov2659_qvga[] = { | |
671 | { REG_TIMING_HS_H, 0x00 }, | |
672 | { REG_TIMING_HS_L, 0x00 }, | |
673 | { REG_TIMING_VS_H, 0x00 }, | |
674 | { REG_TIMING_VS_L, 0x00 }, | |
675 | { REG_TIMING_HW_H, 0x06 }, | |
676 | { REG_TIMING_HW_L, 0x5f }, | |
677 | { REG_TIMING_VH_H, 0x04 }, | |
678 | { REG_TIMING_VH_L, 0xb7 }, | |
679 | { REG_TIMING_DVPHO_H, 0x01 }, | |
680 | { REG_TIMING_DVPHO_L, 0x40 }, | |
681 | { REG_TIMING_DVPVO_H, 0x00 }, | |
682 | { REG_TIMING_DVPVO_L, 0xf0 }, | |
683 | { REG_TIMING_HTS_H, 0x05 }, | |
684 | { REG_TIMING_HTS_L, 0x14 }, | |
685 | { REG_TIMING_VTS_H, 0x02 }, | |
686 | { REG_TIMING_VTS_L, 0x68 }, | |
687 | { REG_TIMING_HOFFS_L, 0x08 }, | |
688 | { REG_TIMING_VOFFS_L, 0x02 }, | |
689 | { REG_TIMING_XINC, 0x31 }, | |
690 | { REG_TIMING_YINC, 0x31 }, | |
691 | { 0x3a02, 0x02 }, | |
692 | { 0x3a03, 0x68 }, | |
693 | { 0x3a08, 0x00 }, | |
694 | { 0x3a09, 0x5c }, | |
695 | { 0x3a0a, 0x00 }, | |
696 | { 0x3a0b, 0x4d }, | |
697 | { 0x3a0d, 0x08 }, | |
698 | { 0x3a0e, 0x06 }, | |
699 | { 0x3a14, 0x02 }, | |
700 | { 0x3a15, 0x28 }, | |
701 | { 0x3623, 0x00 }, | |
702 | { 0x3634, 0x76 }, | |
703 | { 0x3701, 0x44 }, | |
704 | { 0x3702, 0x18 }, | |
705 | { 0x3703, 0x24 }, | |
706 | { 0x3704, 0x24 }, | |
707 | { 0x3705, 0x0c }, | |
708 | { REG_TIMING_VERT_FORMAT, 0x81 }, | |
709 | { REG_TIMING_HORIZ_FORMAT, 0x01 }, | |
710 | { 0x370a, 0x52 }, | |
711 | { REG_VFIFO_READ_START_H, 0x00 }, | |
712 | { REG_VFIFO_READ_START_L, 0x80 }, | |
713 | { REG_ISP_CTRL02, 0x10 }, | |
714 | { REG_NULL, 0x00 }, | |
715 | }; | |
716 | ||
717 | static const struct pll_ctrl_reg ctrl3[] = { | |
718 | { 1, 0x00 }, | |
719 | { 2, 0x02 }, | |
720 | { 3, 0x03 }, | |
721 | { 4, 0x06 }, | |
722 | { 6, 0x0d }, | |
723 | { 8, 0x0e }, | |
724 | { 12, 0x0f }, | |
725 | { 16, 0x12 }, | |
726 | { 24, 0x13 }, | |
727 | { 32, 0x16 }, | |
728 | { 48, 0x1b }, | |
729 | { 64, 0x1e }, | |
730 | { 96, 0x1f }, | |
731 | { 0, 0x00 }, | |
732 | }; | |
733 | ||
734 | static const struct pll_ctrl_reg ctrl1[] = { | |
735 | { 2, 0x10 }, | |
736 | { 4, 0x20 }, | |
737 | { 6, 0x30 }, | |
738 | { 8, 0x40 }, | |
739 | { 10, 0x50 }, | |
740 | { 12, 0x60 }, | |
741 | { 14, 0x70 }, | |
742 | { 16, 0x80 }, | |
743 | { 18, 0x90 }, | |
744 | { 20, 0xa0 }, | |
745 | { 22, 0xb0 }, | |
746 | { 24, 0xc0 }, | |
747 | { 26, 0xd0 }, | |
748 | { 28, 0xe0 }, | |
749 | { 30, 0xf0 }, | |
750 | { 0, 0x00 }, | |
751 | }; | |
752 | ||
753 | static const struct ov2659_framesize ov2659_framesizes[] = { | |
754 | { /* QVGA */ | |
755 | .width = 320, | |
756 | .height = 240, | |
757 | .regs = ov2659_qvga, | |
758 | .max_exp_lines = 248, | |
759 | }, { /* VGA */ | |
760 | .width = 640, | |
761 | .height = 480, | |
762 | .regs = ov2659_vga, | |
763 | .max_exp_lines = 498, | |
764 | }, { /* SVGA */ | |
765 | .width = 800, | |
766 | .height = 600, | |
767 | .regs = ov2659_svga, | |
768 | .max_exp_lines = 498, | |
769 | }, { /* XGA */ | |
770 | .width = 1024, | |
771 | .height = 768, | |
772 | .regs = ov2659_xga, | |
773 | .max_exp_lines = 498, | |
774 | }, { /* 720P */ | |
775 | .width = 1280, | |
776 | .height = 720, | |
777 | .regs = ov2659_720p, | |
778 | .max_exp_lines = 498, | |
779 | }, { /* SXGA */ | |
780 | .width = 1280, | |
781 | .height = 1024, | |
782 | .regs = ov2659_sxga, | |
783 | .max_exp_lines = 1048, | |
784 | }, { /* UXGA */ | |
785 | .width = 1600, | |
786 | .height = 1200, | |
787 | .regs = ov2659_uxga, | |
788 | .max_exp_lines = 498, | |
789 | }, | |
790 | }; | |
791 | ||
792 | /* YUV422 YUYV*/ | |
793 | static struct sensor_register ov2659_format_yuyv[] = { | |
794 | { REG_FORMAT_CTRL00, 0x30 }, | |
795 | { REG_NULL, 0x0 }, | |
796 | }; | |
797 | ||
798 | /* YUV422 UYVY */ | |
799 | static struct sensor_register ov2659_format_uyvy[] = { | |
800 | { REG_FORMAT_CTRL00, 0x32 }, | |
801 | { REG_NULL, 0x0 }, | |
802 | }; | |
803 | ||
804 | /* Raw Bayer BGGR */ | |
805 | static struct sensor_register ov2659_format_bggr[] = { | |
806 | { REG_FORMAT_CTRL00, 0x00 }, | |
807 | { REG_NULL, 0x0 }, | |
808 | }; | |
809 | ||
810 | /* RGB565 */ | |
811 | static struct sensor_register ov2659_format_rgb565[] = { | |
812 | { REG_FORMAT_CTRL00, 0x60 }, | |
813 | { REG_NULL, 0x0 }, | |
814 | }; | |
815 | ||
816 | static const struct ov2659_pixfmt ov2659_formats[] = { | |
817 | { | |
818 | .code = MEDIA_BUS_FMT_YUYV8_2X8, | |
819 | .format_ctrl_regs = ov2659_format_yuyv, | |
820 | }, { | |
821 | .code = MEDIA_BUS_FMT_UYVY8_2X8, | |
822 | .format_ctrl_regs = ov2659_format_uyvy, | |
823 | }, { | |
824 | .code = MEDIA_BUS_FMT_RGB565_2X8_BE, | |
825 | .format_ctrl_regs = ov2659_format_rgb565, | |
826 | }, { | |
827 | .code = MEDIA_BUS_FMT_SBGGR8_1X8, | |
828 | .format_ctrl_regs = ov2659_format_bggr, | |
829 | }, | |
830 | }; | |
831 | ||
832 | static inline struct ov2659 *to_ov2659(struct v4l2_subdev *sd) | |
833 | { | |
834 | return container_of(sd, struct ov2659, sd); | |
835 | } | |
836 | ||
837 | /* sensor register write */ | |
838 | static int ov2659_write(struct i2c_client *client, u16 reg, u8 val) | |
839 | { | |
840 | struct i2c_msg msg; | |
841 | u8 buf[3]; | |
842 | int ret; | |
843 | ||
844 | buf[0] = reg >> 8; | |
845 | buf[1] = reg & 0xFF; | |
846 | buf[2] = val; | |
847 | ||
848 | msg.addr = client->addr; | |
849 | msg.flags = client->flags; | |
850 | msg.buf = buf; | |
851 | msg.len = sizeof(buf); | |
852 | ||
853 | ret = i2c_transfer(client->adapter, &msg, 1); | |
854 | if (ret >= 0) | |
855 | return 0; | |
856 | ||
857 | dev_dbg(&client->dev, | |
858 | "ov2659 write reg(0x%x val:0x%x) failed !\n", reg, val); | |
859 | ||
860 | return ret; | |
861 | } | |
862 | ||
863 | /* sensor register read */ | |
864 | static int ov2659_read(struct i2c_client *client, u16 reg, u8 *val) | |
865 | { | |
866 | struct i2c_msg msg[2]; | |
867 | u8 buf[2]; | |
868 | int ret; | |
869 | ||
870 | buf[0] = reg >> 8; | |
871 | buf[1] = reg & 0xFF; | |
872 | ||
873 | msg[0].addr = client->addr; | |
874 | msg[0].flags = client->flags; | |
875 | msg[0].buf = buf; | |
876 | msg[0].len = sizeof(buf); | |
877 | ||
878 | msg[1].addr = client->addr; | |
879 | msg[1].flags = client->flags | I2C_M_RD; | |
880 | msg[1].buf = buf; | |
881 | msg[1].len = 1; | |
882 | ||
883 | ret = i2c_transfer(client->adapter, msg, 2); | |
884 | if (ret >= 0) { | |
885 | *val = buf[0]; | |
886 | return 0; | |
887 | } | |
888 | ||
889 | dev_dbg(&client->dev, | |
890 | "ov2659 read reg(0x%x val:0x%x) failed !\n", reg, *val); | |
891 | ||
892 | return ret; | |
893 | } | |
894 | ||
895 | static int ov2659_write_array(struct i2c_client *client, | |
896 | const struct sensor_register *regs) | |
897 | { | |
898 | int i, ret = 0; | |
899 | ||
900 | for (i = 0; ret == 0 && regs[i].addr; i++) | |
901 | ret = ov2659_write(client, regs[i].addr, regs[i].value); | |
902 | ||
903 | return ret; | |
904 | } | |
905 | ||
906 | static void ov2659_pll_calc_params(struct ov2659 *ov2659) | |
907 | { | |
908 | const struct ov2659_platform_data *pdata = ov2659->pdata; | |
909 | u8 ctrl1_reg = 0, ctrl2_reg = 0, ctrl3_reg = 0; | |
910 | struct i2c_client *client = ov2659->client; | |
911 | unsigned int desired = pdata->link_frequency; | |
912 | u32 s_prediv = 1, s_postdiv = 1, s_mult = 1; | |
913 | u32 prediv, postdiv, mult; | |
914 | u32 bestdelta = -1; | |
915 | u32 delta, actual; | |
916 | int i, j; | |
917 | ||
918 | for (i = 0; ctrl1[i].div != 0; i++) { | |
919 | postdiv = ctrl1[i].div; | |
920 | for (j = 0; ctrl3[j].div != 0; j++) { | |
921 | prediv = ctrl3[j].div; | |
922 | for (mult = 1; mult <= 63; mult++) { | |
923 | actual = ov2659->xvclk_frequency; | |
924 | actual *= mult; | |
925 | actual /= prediv; | |
926 | actual /= postdiv; | |
927 | delta = actual - desired; | |
928 | delta = abs(delta); | |
929 | ||
930 | if ((delta < bestdelta) || (bestdelta == -1)) { | |
931 | bestdelta = delta; | |
932 | s_mult = mult; | |
933 | s_prediv = prediv; | |
934 | s_postdiv = postdiv; | |
935 | ctrl1_reg = ctrl1[i].reg; | |
936 | ctrl2_reg = mult; | |
937 | ctrl3_reg = ctrl3[j].reg; | |
938 | } | |
939 | } | |
940 | } | |
941 | } | |
942 | ||
943 | ov2659->pll.ctrl1 = ctrl1_reg; | |
944 | ov2659->pll.ctrl2 = ctrl2_reg; | |
945 | ov2659->pll.ctrl3 = ctrl3_reg; | |
946 | ||
947 | dev_dbg(&client->dev, | |
948 | "Actual reg config: ctrl1_reg: %02x ctrl2_reg: %02x ctrl3_reg: %02x\n", | |
949 | ctrl1_reg, ctrl2_reg, ctrl3_reg); | |
950 | } | |
951 | ||
952 | static int ov2659_set_pixel_clock(struct ov2659 *ov2659) | |
953 | { | |
954 | struct i2c_client *client = ov2659->client; | |
955 | struct sensor_register pll_regs[] = { | |
956 | {REG_SC_PLL_CTRL1, ov2659->pll.ctrl1}, | |
957 | {REG_SC_PLL_CTRL2, ov2659->pll.ctrl2}, | |
958 | {REG_SC_PLL_CTRL3, ov2659->pll.ctrl3}, | |
959 | {REG_NULL, 0x00}, | |
960 | }; | |
961 | ||
962 | dev_dbg(&client->dev, "%s\n", __func__); | |
963 | ||
964 | return ov2659_write_array(client, pll_regs); | |
965 | }; | |
966 | ||
967 | static void ov2659_get_default_format(struct v4l2_mbus_framefmt *format) | |
968 | { | |
969 | format->width = ov2659_framesizes[2].width; | |
970 | format->height = ov2659_framesizes[2].height; | |
971 | format->colorspace = V4L2_COLORSPACE_SRGB; | |
972 | format->code = ov2659_formats[0].code; | |
973 | format->field = V4L2_FIELD_NONE; | |
974 | } | |
975 | ||
976 | static void ov2659_set_streaming(struct ov2659 *ov2659, int on) | |
977 | { | |
978 | struct i2c_client *client = ov2659->client; | |
979 | int ret; | |
980 | ||
981 | on = !!on; | |
982 | ||
983 | dev_dbg(&client->dev, "%s: on: %d\n", __func__, on); | |
984 | ||
985 | ret = ov2659_write(client, REG_SOFTWARE_STANDBY, on); | |
986 | if (ret) | |
987 | dev_err(&client->dev, "ov2659 soft standby failed\n"); | |
988 | } | |
989 | ||
990 | static int ov2659_init(struct v4l2_subdev *sd, u32 val) | |
991 | { | |
992 | struct i2c_client *client = v4l2_get_subdevdata(sd); | |
993 | ||
994 | return ov2659_write_array(client, ov2659_init_regs); | |
995 | } | |
996 | ||
997 | /* | |
998 | * V4L2 subdev video and pad level operations | |
999 | */ | |
1000 | ||
1001 | static int ov2659_enum_mbus_code(struct v4l2_subdev *sd, | |
1002 | struct v4l2_subdev_pad_config *cfg, | |
1003 | struct v4l2_subdev_mbus_code_enum *code) | |
1004 | { | |
1005 | struct i2c_client *client = v4l2_get_subdevdata(sd); | |
1006 | ||
1007 | dev_dbg(&client->dev, "%s:\n", __func__); | |
1008 | ||
1009 | if (code->index >= ARRAY_SIZE(ov2659_formats)) | |
1010 | return -EINVAL; | |
1011 | ||
1012 | code->code = ov2659_formats[code->index].code; | |
1013 | ||
1014 | return 0; | |
1015 | } | |
1016 | ||
1017 | static int ov2659_enum_frame_sizes(struct v4l2_subdev *sd, | |
1018 | struct v4l2_subdev_pad_config *cfg, | |
1019 | struct v4l2_subdev_frame_size_enum *fse) | |
1020 | { | |
1021 | struct i2c_client *client = v4l2_get_subdevdata(sd); | |
1022 | int i = ARRAY_SIZE(ov2659_formats); | |
1023 | ||
1024 | dev_dbg(&client->dev, "%s:\n", __func__); | |
1025 | ||
1026 | if (fse->index >= ARRAY_SIZE(ov2659_framesizes)) | |
1027 | return -EINVAL; | |
1028 | ||
1029 | while (--i) | |
1030 | if (fse->code == ov2659_formats[i].code) | |
1031 | break; | |
1032 | ||
1033 | fse->code = ov2659_formats[i].code; | |
1034 | ||
1035 | fse->min_width = ov2659_framesizes[fse->index].width; | |
1036 | fse->max_width = fse->min_width; | |
1037 | fse->max_height = ov2659_framesizes[fse->index].height; | |
1038 | fse->min_height = fse->max_height; | |
1039 | ||
1040 | return 0; | |
1041 | } | |
1042 | ||
1043 | static int ov2659_get_fmt(struct v4l2_subdev *sd, | |
1044 | struct v4l2_subdev_pad_config *cfg, | |
1045 | struct v4l2_subdev_format *fmt) | |
1046 | { | |
1047 | struct i2c_client *client = v4l2_get_subdevdata(sd); | |
1048 | struct ov2659 *ov2659 = to_ov2659(sd); | |
c4c0283a BP |
1049 | |
1050 | dev_dbg(&client->dev, "ov2659_get_fmt\n"); | |
1051 | ||
1052 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { | |
fa8cb644 MCC |
1053 | #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API |
1054 | struct v4l2_mbus_framefmt *mf; | |
1055 | ||
c4c0283a BP |
1056 | mf = v4l2_subdev_get_try_format(sd, cfg, 0); |
1057 | mutex_lock(&ov2659->lock); | |
1058 | fmt->format = *mf; | |
1059 | mutex_unlock(&ov2659->lock); | |
1060 | return 0; | |
fa8cb644 MCC |
1061 | #else |
1062 | return -ENOTTY; | |
1063 | #endif | |
c4c0283a BP |
1064 | } |
1065 | ||
1066 | mutex_lock(&ov2659->lock); | |
1067 | fmt->format = ov2659->format; | |
1068 | mutex_unlock(&ov2659->lock); | |
1069 | ||
1070 | dev_dbg(&client->dev, "ov2659_get_fmt: %x %dx%d\n", | |
1071 | ov2659->format.code, ov2659->format.width, | |
1072 | ov2659->format.height); | |
1073 | ||
1074 | return 0; | |
1075 | } | |
1076 | ||
1077 | static void __ov2659_try_frame_size(struct v4l2_mbus_framefmt *mf, | |
1078 | const struct ov2659_framesize **size) | |
1079 | { | |
1080 | const struct ov2659_framesize *fsize = &ov2659_framesizes[0]; | |
1081 | const struct ov2659_framesize *match = NULL; | |
1082 | int i = ARRAY_SIZE(ov2659_framesizes); | |
1083 | unsigned int min_err = UINT_MAX; | |
1084 | ||
1085 | while (i--) { | |
1086 | int err = abs(fsize->width - mf->width) | |
1087 | + abs(fsize->height - mf->height); | |
1088 | if ((err < min_err) && (fsize->regs[0].addr)) { | |
1089 | min_err = err; | |
1090 | match = fsize; | |
1091 | } | |
1092 | fsize++; | |
1093 | } | |
1094 | ||
1095 | if (!match) | |
1096 | match = &ov2659_framesizes[2]; | |
1097 | ||
1098 | mf->width = match->width; | |
1099 | mf->height = match->height; | |
1100 | ||
1101 | if (size) | |
1102 | *size = match; | |
1103 | } | |
1104 | ||
1105 | static int ov2659_set_fmt(struct v4l2_subdev *sd, | |
1106 | struct v4l2_subdev_pad_config *cfg, | |
1107 | struct v4l2_subdev_format *fmt) | |
1108 | { | |
1109 | struct i2c_client *client = v4l2_get_subdevdata(sd); | |
5f5859d1 | 1110 | int index = ARRAY_SIZE(ov2659_formats); |
c4c0283a BP |
1111 | struct v4l2_mbus_framefmt *mf = &fmt->format; |
1112 | const struct ov2659_framesize *size = NULL; | |
1113 | struct ov2659 *ov2659 = to_ov2659(sd); | |
1114 | int ret = 0; | |
1115 | ||
1116 | dev_dbg(&client->dev, "ov2659_set_fmt\n"); | |
1117 | ||
1118 | __ov2659_try_frame_size(mf, &size); | |
1119 | ||
1120 | while (--index >= 0) | |
1121 | if (ov2659_formats[index].code == mf->code) | |
1122 | break; | |
1123 | ||
1124 | if (index < 0) | |
1125 | return -EINVAL; | |
1126 | ||
1127 | mf->colorspace = V4L2_COLORSPACE_SRGB; | |
1128 | mf->code = ov2659_formats[index].code; | |
1129 | mf->field = V4L2_FIELD_NONE; | |
1130 | ||
1131 | mutex_lock(&ov2659->lock); | |
1132 | ||
1133 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { | |
fa8cb644 | 1134 | #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API |
c4c0283a BP |
1135 | mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); |
1136 | *mf = fmt->format; | |
fa8cb644 MCC |
1137 | #else |
1138 | return -ENOTTY; | |
1139 | #endif | |
c4c0283a BP |
1140 | } else { |
1141 | s64 val; | |
1142 | ||
1143 | if (ov2659->streaming) { | |
1144 | mutex_unlock(&ov2659->lock); | |
1145 | return -EBUSY; | |
1146 | } | |
1147 | ||
1148 | ov2659->frame_size = size; | |
1149 | ov2659->format = fmt->format; | |
1150 | ov2659->format_ctrl_regs = | |
1151 | ov2659_formats[index].format_ctrl_regs; | |
1152 | ||
1153 | if (ov2659->format.code != MEDIA_BUS_FMT_SBGGR8_1X8) | |
1154 | val = ov2659->pdata->link_frequency / 2; | |
1155 | else | |
1156 | val = ov2659->pdata->link_frequency; | |
1157 | ||
1158 | ret = v4l2_ctrl_s_ctrl_int64(ov2659->link_frequency, val); | |
1159 | if (ret < 0) | |
1160 | dev_warn(&client->dev, | |
1161 | "failed to set link_frequency rate (%d)\n", | |
1162 | ret); | |
1163 | } | |
1164 | ||
1165 | mutex_unlock(&ov2659->lock); | |
1166 | return ret; | |
1167 | } | |
1168 | ||
1169 | static int ov2659_set_frame_size(struct ov2659 *ov2659) | |
1170 | { | |
1171 | struct i2c_client *client = ov2659->client; | |
1172 | ||
1173 | dev_dbg(&client->dev, "%s\n", __func__); | |
1174 | ||
1175 | return ov2659_write_array(ov2659->client, ov2659->frame_size->regs); | |
1176 | } | |
1177 | ||
1178 | static int ov2659_set_format(struct ov2659 *ov2659) | |
1179 | { | |
1180 | struct i2c_client *client = ov2659->client; | |
1181 | ||
1182 | dev_dbg(&client->dev, "%s\n", __func__); | |
1183 | ||
1184 | return ov2659_write_array(ov2659->client, ov2659->format_ctrl_regs); | |
1185 | } | |
1186 | ||
1187 | static int ov2659_s_stream(struct v4l2_subdev *sd, int on) | |
1188 | { | |
1189 | struct i2c_client *client = v4l2_get_subdevdata(sd); | |
1190 | struct ov2659 *ov2659 = to_ov2659(sd); | |
1191 | int ret = 0; | |
1192 | ||
1193 | dev_dbg(&client->dev, "%s: on: %d\n", __func__, on); | |
1194 | ||
1195 | mutex_lock(&ov2659->lock); | |
1196 | ||
1197 | on = !!on; | |
1198 | ||
1199 | if (ov2659->streaming == on) | |
1200 | goto unlock; | |
1201 | ||
1202 | if (!on) { | |
1203 | /* Stop Streaming Sequence */ | |
1204 | ov2659_set_streaming(ov2659, 0); | |
1205 | ov2659->streaming = on; | |
1206 | goto unlock; | |
1207 | } | |
1208 | ||
1209 | ov2659_set_pixel_clock(ov2659); | |
1210 | ov2659_set_frame_size(ov2659); | |
1211 | ov2659_set_format(ov2659); | |
1212 | ov2659_set_streaming(ov2659, 1); | |
1213 | ov2659->streaming = on; | |
1214 | ||
1215 | unlock: | |
1216 | mutex_unlock(&ov2659->lock); | |
1217 | return ret; | |
1218 | } | |
1219 | ||
1220 | static int ov2659_set_test_pattern(struct ov2659 *ov2659, int value) | |
1221 | { | |
1222 | struct i2c_client *client = v4l2_get_subdevdata(&ov2659->sd); | |
1223 | int ret; | |
1224 | u8 val; | |
1225 | ||
1226 | ret = ov2659_read(client, REG_PRE_ISP_CTRL00, &val); | |
1227 | if (ret < 0) | |
1228 | return ret; | |
1229 | ||
1230 | switch (value) { | |
1231 | case 0: | |
1232 | val &= ~TEST_PATTERN_ENABLE; | |
1233 | break; | |
1234 | case 1: | |
1235 | val &= VERTICAL_COLOR_BAR_MASK; | |
1236 | val |= TEST_PATTERN_ENABLE; | |
1237 | break; | |
1238 | } | |
1239 | ||
1240 | return ov2659_write(client, REG_PRE_ISP_CTRL00, val); | |
1241 | } | |
1242 | ||
1243 | static int ov2659_s_ctrl(struct v4l2_ctrl *ctrl) | |
1244 | { | |
1245 | struct ov2659 *ov2659 = | |
1246 | container_of(ctrl->handler, struct ov2659, ctrls); | |
1247 | ||
1248 | switch (ctrl->id) { | |
1249 | case V4L2_CID_TEST_PATTERN: | |
1250 | return ov2659_set_test_pattern(ov2659, ctrl->val); | |
1251 | } | |
1252 | ||
1253 | return 0; | |
1254 | } | |
1255 | ||
1256 | static struct v4l2_ctrl_ops ov2659_ctrl_ops = { | |
1257 | .s_ctrl = ov2659_s_ctrl, | |
1258 | }; | |
1259 | ||
1260 | static const char * const ov2659_test_pattern_menu[] = { | |
1261 | "Disabled", | |
1262 | "Vertical Color Bars", | |
1263 | }; | |
1264 | ||
1265 | /* ----------------------------------------------------------------------------- | |
1266 | * V4L2 subdev internal operations | |
1267 | */ | |
1268 | ||
fa8cb644 | 1269 | #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API |
c4c0283a BP |
1270 | static int ov2659_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) |
1271 | { | |
1272 | struct i2c_client *client = v4l2_get_subdevdata(sd); | |
1273 | struct v4l2_mbus_framefmt *format = | |
1274 | v4l2_subdev_get_try_format(sd, fh->pad, 0); | |
1275 | ||
1276 | dev_dbg(&client->dev, "%s:\n", __func__); | |
1277 | ||
1278 | ov2659_get_default_format(format); | |
1279 | ||
1280 | return 0; | |
1281 | } | |
fa8cb644 | 1282 | #endif |
c4c0283a BP |
1283 | |
1284 | static const struct v4l2_subdev_core_ops ov2659_subdev_core_ops = { | |
1285 | .log_status = v4l2_ctrl_subdev_log_status, | |
1286 | .subscribe_event = v4l2_ctrl_subdev_subscribe_event, | |
1287 | .unsubscribe_event = v4l2_event_subdev_unsubscribe, | |
1288 | }; | |
1289 | ||
1290 | static const struct v4l2_subdev_video_ops ov2659_subdev_video_ops = { | |
1291 | .s_stream = ov2659_s_stream, | |
1292 | }; | |
1293 | ||
1294 | static const struct v4l2_subdev_pad_ops ov2659_subdev_pad_ops = { | |
1295 | .enum_mbus_code = ov2659_enum_mbus_code, | |
1296 | .enum_frame_size = ov2659_enum_frame_sizes, | |
1297 | .get_fmt = ov2659_get_fmt, | |
1298 | .set_fmt = ov2659_set_fmt, | |
1299 | }; | |
1300 | ||
fa8cb644 | 1301 | #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API |
c4c0283a BP |
1302 | static const struct v4l2_subdev_ops ov2659_subdev_ops = { |
1303 | .core = &ov2659_subdev_core_ops, | |
1304 | .video = &ov2659_subdev_video_ops, | |
1305 | .pad = &ov2659_subdev_pad_ops, | |
1306 | }; | |
1307 | ||
1308 | static const struct v4l2_subdev_internal_ops ov2659_subdev_internal_ops = { | |
1309 | .open = ov2659_open, | |
1310 | }; | |
fa8cb644 | 1311 | #endif |
c4c0283a BP |
1312 | |
1313 | static int ov2659_detect(struct v4l2_subdev *sd) | |
1314 | { | |
1315 | struct i2c_client *client = v4l2_get_subdevdata(sd); | |
1316 | u8 pid, ver; | |
1317 | int ret; | |
1318 | ||
1319 | dev_dbg(&client->dev, "%s:\n", __func__); | |
1320 | ||
1321 | ret = ov2659_write(client, REG_SOFTWARE_RESET, 0x01); | |
1322 | if (ret != 0) { | |
1323 | dev_err(&client->dev, "Sensor soft reset failed\n"); | |
1324 | return -ENODEV; | |
1325 | } | |
1326 | usleep_range(1000, 2000); | |
1327 | ||
1328 | ret = ov2659_init(sd, 0); | |
1329 | if (ret < 0) | |
1330 | return ret; | |
1331 | ||
1332 | /* Check sensor revision */ | |
1333 | ret = ov2659_read(client, REG_SC_CHIP_ID_H, &pid); | |
1334 | if (!ret) | |
1335 | ret = ov2659_read(client, REG_SC_CHIP_ID_L, &ver); | |
1336 | ||
1337 | if (!ret) { | |
1338 | unsigned short id; | |
1339 | ||
1340 | id = OV265X_ID(pid, ver); | |
1341 | if (id != OV2659_ID) | |
1342 | dev_err(&client->dev, | |
1343 | "Sensor detection failed (%04X, %d)\n", | |
1344 | id, ret); | |
1345 | else | |
1346 | dev_info(&client->dev, "Found OV%04X sensor\n", id); | |
1347 | } | |
1348 | ||
1349 | return ret; | |
1350 | } | |
1351 | ||
1352 | static struct ov2659_platform_data * | |
1353 | ov2659_get_pdata(struct i2c_client *client) | |
1354 | { | |
1355 | struct ov2659_platform_data *pdata; | |
b3ab190f | 1356 | struct v4l2_of_endpoint *bus_cfg; |
c4c0283a | 1357 | struct device_node *endpoint; |
c4c0283a BP |
1358 | |
1359 | if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node) | |
1360 | return client->dev.platform_data; | |
1361 | ||
1362 | endpoint = of_graph_get_next_endpoint(client->dev.of_node, NULL); | |
1363 | if (!endpoint) | |
1364 | return NULL; | |
1365 | ||
b3ab190f LP |
1366 | bus_cfg = v4l2_of_alloc_parse_endpoint(endpoint); |
1367 | if (IS_ERR(bus_cfg)) { | |
1368 | pdata = NULL; | |
1369 | goto done; | |
1370 | } | |
1371 | ||
c4c0283a BP |
1372 | pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); |
1373 | if (!pdata) | |
1374 | goto done; | |
1375 | ||
b3ab190f LP |
1376 | if (!bus_cfg->nr_of_link_frequencies) { |
1377 | dev_err(&client->dev, | |
1378 | "link-frequencies property not found or too many\n"); | |
c4c0283a | 1379 | pdata = NULL; |
b3ab190f | 1380 | goto done; |
c4c0283a BP |
1381 | } |
1382 | ||
b3ab190f LP |
1383 | pdata->link_frequency = bus_cfg->link_frequencies[0]; |
1384 | ||
c4c0283a | 1385 | done: |
b3ab190f | 1386 | v4l2_of_free_endpoint(bus_cfg); |
c4c0283a BP |
1387 | of_node_put(endpoint); |
1388 | return pdata; | |
1389 | } | |
1390 | ||
1391 | static int ov2659_probe(struct i2c_client *client, | |
1392 | const struct i2c_device_id *id) | |
1393 | { | |
1394 | const struct ov2659_platform_data *pdata = ov2659_get_pdata(client); | |
1395 | struct v4l2_subdev *sd; | |
1396 | struct ov2659 *ov2659; | |
1397 | struct clk *clk; | |
1398 | int ret; | |
1399 | ||
1400 | if (!pdata) { | |
1401 | dev_err(&client->dev, "platform data not specified\n"); | |
1402 | return -EINVAL; | |
1403 | } | |
1404 | ||
1405 | ov2659 = devm_kzalloc(&client->dev, sizeof(*ov2659), GFP_KERNEL); | |
1406 | if (!ov2659) | |
1407 | return -ENOMEM; | |
1408 | ||
1409 | ov2659->pdata = pdata; | |
1410 | ov2659->client = client; | |
1411 | ||
1412 | clk = devm_clk_get(&client->dev, "xvclk"); | |
1413 | if (IS_ERR(clk)) | |
1414 | return PTR_ERR(clk); | |
1415 | ||
1416 | ov2659->xvclk_frequency = clk_get_rate(clk); | |
1417 | if (ov2659->xvclk_frequency < 6000000 || | |
1418 | ov2659->xvclk_frequency > 27000000) | |
1419 | return -EINVAL; | |
1420 | ||
1421 | v4l2_ctrl_handler_init(&ov2659->ctrls, 2); | |
1422 | ov2659->link_frequency = | |
1423 | v4l2_ctrl_new_std(&ov2659->ctrls, &ov2659_ctrl_ops, | |
1424 | V4L2_CID_PIXEL_RATE, | |
1425 | pdata->link_frequency / 2, | |
1426 | pdata->link_frequency, 1, | |
1427 | pdata->link_frequency); | |
1428 | v4l2_ctrl_new_std_menu_items(&ov2659->ctrls, &ov2659_ctrl_ops, | |
1429 | V4L2_CID_TEST_PATTERN, | |
1430 | ARRAY_SIZE(ov2659_test_pattern_menu) - 1, | |
1431 | 0, 0, ov2659_test_pattern_menu); | |
1432 | ov2659->sd.ctrl_handler = &ov2659->ctrls; | |
1433 | ||
1434 | if (ov2659->ctrls.error) { | |
1435 | dev_err(&client->dev, "%s: control initialization error %d\n", | |
1436 | __func__, ov2659->ctrls.error); | |
1437 | return ov2659->ctrls.error; | |
1438 | } | |
1439 | ||
1440 | sd = &ov2659->sd; | |
1441 | client->flags |= I2C_CLIENT_SCCB; | |
fa8cb644 | 1442 | #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API |
c4c0283a BP |
1443 | v4l2_i2c_subdev_init(sd, client, &ov2659_subdev_ops); |
1444 | ||
1445 | sd->internal_ops = &ov2659_subdev_internal_ops; | |
1446 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | | |
1447 | V4L2_SUBDEV_FL_HAS_EVENTS; | |
fa8cb644 | 1448 | #endif |
c4c0283a BP |
1449 | |
1450 | #if defined(CONFIG_MEDIA_CONTROLLER) | |
1451 | ov2659->pad.flags = MEDIA_PAD_FL_SOURCE; | |
1452 | sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; | |
1453 | ret = media_entity_init(&sd->entity, 1, &ov2659->pad, 0); | |
1454 | if (ret < 0) { | |
1455 | v4l2_ctrl_handler_free(&ov2659->ctrls); | |
1456 | return ret; | |
1457 | } | |
1458 | #endif | |
1459 | ||
1460 | mutex_init(&ov2659->lock); | |
1461 | ||
1462 | ov2659_get_default_format(&ov2659->format); | |
1463 | ov2659->frame_size = &ov2659_framesizes[2]; | |
1464 | ov2659->format_ctrl_regs = ov2659_formats[0].format_ctrl_regs; | |
1465 | ||
1466 | ret = ov2659_detect(sd); | |
1467 | if (ret < 0) | |
1468 | goto error; | |
1469 | ||
1470 | /* Calculate the PLL register value needed */ | |
1471 | ov2659_pll_calc_params(ov2659); | |
1472 | ||
1473 | ret = v4l2_async_register_subdev(&ov2659->sd); | |
1474 | if (ret) | |
1475 | goto error; | |
1476 | ||
1477 | dev_info(&client->dev, "%s sensor driver registered !!\n", sd->name); | |
1478 | ||
1479 | return 0; | |
1480 | ||
1481 | error: | |
1482 | v4l2_ctrl_handler_free(&ov2659->ctrls); | |
1483 | #if defined(CONFIG_MEDIA_CONTROLLER) | |
1484 | media_entity_cleanup(&sd->entity); | |
1485 | #endif | |
1486 | mutex_destroy(&ov2659->lock); | |
1487 | return ret; | |
1488 | } | |
1489 | ||
1490 | static int ov2659_remove(struct i2c_client *client) | |
1491 | { | |
1492 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | |
1493 | struct ov2659 *ov2659 = to_ov2659(sd); | |
1494 | ||
1495 | v4l2_ctrl_handler_free(&ov2659->ctrls); | |
1496 | v4l2_async_unregister_subdev(sd); | |
1497 | #if defined(CONFIG_MEDIA_CONTROLLER) | |
1498 | media_entity_cleanup(&sd->entity); | |
1499 | #endif | |
1500 | mutex_destroy(&ov2659->lock); | |
1501 | ||
1502 | return 0; | |
1503 | } | |
1504 | ||
1505 | static const struct i2c_device_id ov2659_id[] = { | |
1506 | { "ov2659", 0 }, | |
1507 | { /* sentinel */ }, | |
1508 | }; | |
1509 | MODULE_DEVICE_TABLE(i2c, ov2659_id); | |
1510 | ||
1511 | #if IS_ENABLED(CONFIG_OF) | |
1512 | static const struct of_device_id ov2659_of_match[] = { | |
1513 | { .compatible = "ovti,ov2659", }, | |
1514 | { /* sentinel */ }, | |
1515 | }; | |
1516 | MODULE_DEVICE_TABLE(of, ov2659_of_match); | |
1517 | #endif | |
1518 | ||
1519 | static struct i2c_driver ov2659_i2c_driver = { | |
1520 | .driver = { | |
1521 | .name = DRIVER_NAME, | |
1522 | .of_match_table = of_match_ptr(ov2659_of_match), | |
1523 | }, | |
1524 | .probe = ov2659_probe, | |
1525 | .remove = ov2659_remove, | |
1526 | .id_table = ov2659_id, | |
1527 | }; | |
1528 | ||
1529 | module_i2c_driver(ov2659_i2c_driver); | |
1530 | ||
1531 | MODULE_AUTHOR("Benoit Parrot <bparrot@ti.com>"); | |
1532 | MODULE_DESCRIPTION("OV2659 CMOS Image Sensor driver"); | |
1533 | MODULE_LICENSE("GPL v2"); |