1/***************************************************************************
2 * Plug-in for OV7660 image sensor connected to the SN9C1xx PC Camera      *
3 * Controllers                                                             *
4 *                                                                         *
5 * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it>       *
6 *                                                                         *
7 * This program is free software; you can redistribute it and/or modify    *
8 * it under the terms of the GNU General Public License as published by    *
9 * the Free Software Foundation; either version 2 of the License, or       *
10 * (at your option) any later version.                                     *
11 *                                                                         *
12 * This program is distributed in the hope that it will be useful,         *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
15 * GNU General Public License for more details.                            *
16 *                                                                         *
17 * You should have received a copy of the GNU General Public License       *
18 * along with this program; if not, write to the Free Software             *
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
20 ***************************************************************************/
21
22#include "sn9c102_sensor.h"
23
24
25static int ov7660_init(struct sn9c102_device* cam)
26{
27	int err = 0;
28
29	err = sn9c102_write_const_regs(cam, {0x40, 0x02}, {0x00, 0x03},
30				       {0x1a, 0x04}, {0x03, 0x10},
31				       {0x08, 0x14}, {0x20, 0x17},
32				       {0x8b, 0x18}, {0x00, 0x19},
33				       {0x1d, 0x1a}, {0x10, 0x1b},
34				       {0x02, 0x1c}, {0x03, 0x1d},
35				       {0x0f, 0x1e}, {0x0c, 0x1f},
36				       {0x00, 0x20}, {0x29, 0x21},
37				       {0x40, 0x22}, {0x54, 0x23},
38				       {0x66, 0x24}, {0x76, 0x25},
39				       {0x85, 0x26}, {0x94, 0x27},
40				       {0xa1, 0x28}, {0xae, 0x29},
41				       {0xbb, 0x2a}, {0xc7, 0x2b},
42				       {0xd3, 0x2c}, {0xde, 0x2d},
43				       {0xea, 0x2e}, {0xf4, 0x2f},
44				       {0xff, 0x30}, {0x00, 0x3F},
45				       {0xC7, 0x40}, {0x01, 0x41},
46				       {0x44, 0x42}, {0x00, 0x43},
47				       {0x44, 0x44}, {0x00, 0x45},
48				       {0x44, 0x46}, {0x00, 0x47},
49				       {0xC7, 0x48}, {0x01, 0x49},
50				       {0xC7, 0x4A}, {0x01, 0x4B},
51				       {0xC7, 0x4C}, {0x01, 0x4D},
52				       {0x44, 0x4E}, {0x00, 0x4F},
53				       {0x44, 0x50}, {0x00, 0x51},
54				       {0x44, 0x52}, {0x00, 0x53},
55				       {0xC7, 0x54}, {0x01, 0x55},
56				       {0xC7, 0x56}, {0x01, 0x57},
57				       {0xC7, 0x58}, {0x01, 0x59},
58				       {0x44, 0x5A}, {0x00, 0x5B},
59				       {0x44, 0x5C}, {0x00, 0x5D},
60				       {0x44, 0x5E}, {0x00, 0x5F},
61				       {0xC7, 0x60}, {0x01, 0x61},
62				       {0xC7, 0x62}, {0x01, 0x63},
63				       {0xC7, 0x64}, {0x01, 0x65},
64				       {0x44, 0x66}, {0x00, 0x67},
65				       {0x44, 0x68}, {0x00, 0x69},
66				       {0x44, 0x6A}, {0x00, 0x6B},
67				       {0xC7, 0x6C}, {0x01, 0x6D},
68				       {0xC7, 0x6E}, {0x01, 0x6F},
69				       {0xC7, 0x70}, {0x01, 0x71},
70				       {0x44, 0x72}, {0x00, 0x73},
71				       {0x44, 0x74}, {0x00, 0x75},
72				       {0x44, 0x76}, {0x00, 0x77},
73				       {0xC7, 0x78}, {0x01, 0x79},
74				       {0xC7, 0x7A}, {0x01, 0x7B},
75				       {0xC7, 0x7C}, {0x01, 0x7D},
76				       {0x44, 0x7E}, {0x00, 0x7F},
77				       {0x14, 0x84}, {0x00, 0x85},
78				       {0x27, 0x86}, {0x00, 0x87},
79				       {0x07, 0x88}, {0x00, 0x89},
80				       {0xEC, 0x8A}, {0x0f, 0x8B},
81				       {0xD8, 0x8C}, {0x0f, 0x8D},
82				       {0x3D, 0x8E}, {0x00, 0x8F},
83				       {0x3D, 0x90}, {0x00, 0x91},
84				       {0xCD, 0x92}, {0x0f, 0x93},
85				       {0xf7, 0x94}, {0x0f, 0x95},
86				       {0x0C, 0x96}, {0x00, 0x97},
87				       {0x00, 0x98}, {0x66, 0x99},
88				       {0x05, 0x9A}, {0x00, 0x9B},
89				       {0x04, 0x9C}, {0x00, 0x9D},
90				       {0x08, 0x9E}, {0x00, 0x9F},
91				       {0x2D, 0xC0}, {0x2D, 0xC1},
92				       {0x3A, 0xC2}, {0x05, 0xC3},
93				       {0x04, 0xC4}, {0x3F, 0xC5},
94				       {0x00, 0xC6}, {0x00, 0xC7},
95				       {0x50, 0xC8}, {0x3C, 0xC9},
96				       {0x28, 0xCA}, {0xD8, 0xCB},
97				       {0x14, 0xCC}, {0xEC, 0xCD},
98				       {0x32, 0xCE}, {0xDD, 0xCF},
99				       {0x32, 0xD0}, {0xDD, 0xD1},
100				       {0x6A, 0xD2}, {0x50, 0xD3},
101				       {0x00, 0xD4}, {0x00, 0xD5},
102				       {0x00, 0xD6});
103
104	err += sn9c102_i2c_write(cam, 0x12, 0x80);
105	err += sn9c102_i2c_write(cam, 0x11, 0x09);
106	err += sn9c102_i2c_write(cam, 0x00, 0x0A);
107	err += sn9c102_i2c_write(cam, 0x01, 0x80);
108	err += sn9c102_i2c_write(cam, 0x02, 0x80);
109	err += sn9c102_i2c_write(cam, 0x03, 0x00);
110	err += sn9c102_i2c_write(cam, 0x04, 0x00);
111	err += sn9c102_i2c_write(cam, 0x05, 0x08);
112	err += sn9c102_i2c_write(cam, 0x06, 0x0B);
113	err += sn9c102_i2c_write(cam, 0x07, 0x00);
114	err += sn9c102_i2c_write(cam, 0x08, 0x1C);
115	err += sn9c102_i2c_write(cam, 0x09, 0x01);
116	err += sn9c102_i2c_write(cam, 0x0A, 0x76);
117	err += sn9c102_i2c_write(cam, 0x0B, 0x60);
118	err += sn9c102_i2c_write(cam, 0x0C, 0x00);
119	err += sn9c102_i2c_write(cam, 0x0D, 0x08);
120	err += sn9c102_i2c_write(cam, 0x0E, 0x04);
121	err += sn9c102_i2c_write(cam, 0x0F, 0x6F);
122	err += sn9c102_i2c_write(cam, 0x10, 0x20);
123	err += sn9c102_i2c_write(cam, 0x11, 0x03);
124	err += sn9c102_i2c_write(cam, 0x12, 0x05);
125	err += sn9c102_i2c_write(cam, 0x13, 0xC7);
126	err += sn9c102_i2c_write(cam, 0x14, 0x2C);
127	err += sn9c102_i2c_write(cam, 0x15, 0x00);
128	err += sn9c102_i2c_write(cam, 0x16, 0x02);
129	err += sn9c102_i2c_write(cam, 0x17, 0x10);
130	err += sn9c102_i2c_write(cam, 0x18, 0x60);
131	err += sn9c102_i2c_write(cam, 0x19, 0x02);
132	err += sn9c102_i2c_write(cam, 0x1A, 0x7B);
133	err += sn9c102_i2c_write(cam, 0x1B, 0x02);
134	err += sn9c102_i2c_write(cam, 0x1C, 0x7F);
135	err += sn9c102_i2c_write(cam, 0x1D, 0xA2);
136	err += sn9c102_i2c_write(cam, 0x1E, 0x01);
137	err += sn9c102_i2c_write(cam, 0x1F, 0x0E);
138	err += sn9c102_i2c_write(cam, 0x20, 0x05);
139	err += sn9c102_i2c_write(cam, 0x21, 0x05);
140	err += sn9c102_i2c_write(cam, 0x22, 0x05);
141	err += sn9c102_i2c_write(cam, 0x23, 0x05);
142	err += sn9c102_i2c_write(cam, 0x24, 0x68);
143	err += sn9c102_i2c_write(cam, 0x25, 0x58);
144	err += sn9c102_i2c_write(cam, 0x26, 0xD4);
145	err += sn9c102_i2c_write(cam, 0x27, 0x80);
146	err += sn9c102_i2c_write(cam, 0x28, 0x80);
147	err += sn9c102_i2c_write(cam, 0x29, 0x30);
148	err += sn9c102_i2c_write(cam, 0x2A, 0x00);
149	err += sn9c102_i2c_write(cam, 0x2B, 0x00);
150	err += sn9c102_i2c_write(cam, 0x2C, 0x80);
151	err += sn9c102_i2c_write(cam, 0x2D, 0x00);
152	err += sn9c102_i2c_write(cam, 0x2E, 0x00);
153	err += sn9c102_i2c_write(cam, 0x2F, 0x0E);
154	err += sn9c102_i2c_write(cam, 0x30, 0x08);
155	err += sn9c102_i2c_write(cam, 0x31, 0x30);
156	err += sn9c102_i2c_write(cam, 0x32, 0xB4);
157	err += sn9c102_i2c_write(cam, 0x33, 0x00);
158	err += sn9c102_i2c_write(cam, 0x34, 0x07);
159	err += sn9c102_i2c_write(cam, 0x35, 0x84);
160	err += sn9c102_i2c_write(cam, 0x36, 0x00);
161	err += sn9c102_i2c_write(cam, 0x37, 0x0C);
162	err += sn9c102_i2c_write(cam, 0x38, 0x02);
163	err += sn9c102_i2c_write(cam, 0x39, 0x43);
164	err += sn9c102_i2c_write(cam, 0x3A, 0x00);
165	err += sn9c102_i2c_write(cam, 0x3B, 0x0A);
166	err += sn9c102_i2c_write(cam, 0x3C, 0x6C);
167	err += sn9c102_i2c_write(cam, 0x3D, 0x99);
168	err += sn9c102_i2c_write(cam, 0x3E, 0x0E);
169	err += sn9c102_i2c_write(cam, 0x3F, 0x41);
170	err += sn9c102_i2c_write(cam, 0x40, 0xC1);
171	err += sn9c102_i2c_write(cam, 0x41, 0x22);
172	err += sn9c102_i2c_write(cam, 0x42, 0x08);
173	err += sn9c102_i2c_write(cam, 0x43, 0xF0);
174	err += sn9c102_i2c_write(cam, 0x44, 0x10);
175	err += sn9c102_i2c_write(cam, 0x45, 0x78);
176	err += sn9c102_i2c_write(cam, 0x46, 0xA8);
177	err += sn9c102_i2c_write(cam, 0x47, 0x60);
178	err += sn9c102_i2c_write(cam, 0x48, 0x80);
179	err += sn9c102_i2c_write(cam, 0x49, 0x00);
180	err += sn9c102_i2c_write(cam, 0x4A, 0x00);
181	err += sn9c102_i2c_write(cam, 0x4B, 0x00);
182	err += sn9c102_i2c_write(cam, 0x4C, 0x00);
183	err += sn9c102_i2c_write(cam, 0x4D, 0x00);
184	err += sn9c102_i2c_write(cam, 0x4E, 0x00);
185	err += sn9c102_i2c_write(cam, 0x4F, 0x46);
186	err += sn9c102_i2c_write(cam, 0x50, 0x36);
187	err += sn9c102_i2c_write(cam, 0x51, 0x0F);
188	err += sn9c102_i2c_write(cam, 0x52, 0x17);
189	err += sn9c102_i2c_write(cam, 0x53, 0x7F);
190	err += sn9c102_i2c_write(cam, 0x54, 0x96);
191	err += sn9c102_i2c_write(cam, 0x55, 0x40);
192	err += sn9c102_i2c_write(cam, 0x56, 0x40);
193	err += sn9c102_i2c_write(cam, 0x57, 0x40);
194	err += sn9c102_i2c_write(cam, 0x58, 0x0F);
195	err += sn9c102_i2c_write(cam, 0x59, 0xBA);
196	err += sn9c102_i2c_write(cam, 0x5A, 0x9A);
197	err += sn9c102_i2c_write(cam, 0x5B, 0x22);
198	err += sn9c102_i2c_write(cam, 0x5C, 0xB9);
199	err += sn9c102_i2c_write(cam, 0x5D, 0x9B);
200	err += sn9c102_i2c_write(cam, 0x5E, 0x10);
201	err += sn9c102_i2c_write(cam, 0x5F, 0xF0);
202	err += sn9c102_i2c_write(cam, 0x60, 0x05);
203	err += sn9c102_i2c_write(cam, 0x61, 0x60);
204	err += sn9c102_i2c_write(cam, 0x62, 0x00);
205	err += sn9c102_i2c_write(cam, 0x63, 0x00);
206	err += sn9c102_i2c_write(cam, 0x64, 0x50);
207	err += sn9c102_i2c_write(cam, 0x65, 0x30);
208	err += sn9c102_i2c_write(cam, 0x66, 0x00);
209	err += sn9c102_i2c_write(cam, 0x67, 0x80);
210	err += sn9c102_i2c_write(cam, 0x68, 0x7A);
211	err += sn9c102_i2c_write(cam, 0x69, 0x90);
212	err += sn9c102_i2c_write(cam, 0x6A, 0x80);
213	err += sn9c102_i2c_write(cam, 0x6B, 0x0A);
214	err += sn9c102_i2c_write(cam, 0x6C, 0x30);
215	err += sn9c102_i2c_write(cam, 0x6D, 0x48);
216	err += sn9c102_i2c_write(cam, 0x6E, 0x80);
217	err += sn9c102_i2c_write(cam, 0x6F, 0x74);
218	err += sn9c102_i2c_write(cam, 0x70, 0x64);
219	err += sn9c102_i2c_write(cam, 0x71, 0x60);
220	err += sn9c102_i2c_write(cam, 0x72, 0x5C);
221	err += sn9c102_i2c_write(cam, 0x73, 0x58);
222	err += sn9c102_i2c_write(cam, 0x74, 0x54);
223	err += sn9c102_i2c_write(cam, 0x75, 0x4C);
224	err += sn9c102_i2c_write(cam, 0x76, 0x40);
225	err += sn9c102_i2c_write(cam, 0x77, 0x38);
226	err += sn9c102_i2c_write(cam, 0x78, 0x34);
227	err += sn9c102_i2c_write(cam, 0x79, 0x30);
228	err += sn9c102_i2c_write(cam, 0x7A, 0x2F);
229	err += sn9c102_i2c_write(cam, 0x7B, 0x2B);
230	err += sn9c102_i2c_write(cam, 0x7C, 0x03);
231	err += sn9c102_i2c_write(cam, 0x7D, 0x07);
232	err += sn9c102_i2c_write(cam, 0x7E, 0x17);
233	err += sn9c102_i2c_write(cam, 0x7F, 0x34);
234	err += sn9c102_i2c_write(cam, 0x80, 0x41);
235	err += sn9c102_i2c_write(cam, 0x81, 0x4D);
236	err += sn9c102_i2c_write(cam, 0x82, 0x58);
237	err += sn9c102_i2c_write(cam, 0x83, 0x63);
238	err += sn9c102_i2c_write(cam, 0x84, 0x6E);
239	err += sn9c102_i2c_write(cam, 0x85, 0x77);
240	err += sn9c102_i2c_write(cam, 0x86, 0x87);
241	err += sn9c102_i2c_write(cam, 0x87, 0x95);
242	err += sn9c102_i2c_write(cam, 0x88, 0xAF);
243	err += sn9c102_i2c_write(cam, 0x89, 0xC7);
244	err += sn9c102_i2c_write(cam, 0x8A, 0xDF);
245	err += sn9c102_i2c_write(cam, 0x8B, 0x99);
246	err += sn9c102_i2c_write(cam, 0x8C, 0x99);
247	err += sn9c102_i2c_write(cam, 0x8D, 0xCF);
248	err += sn9c102_i2c_write(cam, 0x8E, 0x20);
249	err += sn9c102_i2c_write(cam, 0x8F, 0x26);
250	err += sn9c102_i2c_write(cam, 0x90, 0x10);
251	err += sn9c102_i2c_write(cam, 0x91, 0x0C);
252	err += sn9c102_i2c_write(cam, 0x92, 0x25);
253	err += sn9c102_i2c_write(cam, 0x93, 0x00);
254	err += sn9c102_i2c_write(cam, 0x94, 0x50);
255	err += sn9c102_i2c_write(cam, 0x95, 0x50);
256	err += sn9c102_i2c_write(cam, 0x96, 0x00);
257	err += sn9c102_i2c_write(cam, 0x97, 0x01);
258	err += sn9c102_i2c_write(cam, 0x98, 0x10);
259	err += sn9c102_i2c_write(cam, 0x99, 0x40);
260	err += sn9c102_i2c_write(cam, 0x9A, 0x40);
261	err += sn9c102_i2c_write(cam, 0x9B, 0x20);
262	err += sn9c102_i2c_write(cam, 0x9C, 0x00);
263	err += sn9c102_i2c_write(cam, 0x9D, 0x99);
264	err += sn9c102_i2c_write(cam, 0x9E, 0x7F);
265	err += sn9c102_i2c_write(cam, 0x9F, 0x00);
266	err += sn9c102_i2c_write(cam, 0xA0, 0x00);
267	err += sn9c102_i2c_write(cam, 0xA1, 0x00);
268
269	return err;
270}
271
272
273static int ov7660_get_ctrl(struct sn9c102_device* cam,
274			   struct v4l2_control* ctrl)
275{
276	int err = 0;
277
278	switch (ctrl->id) {
279	case V4L2_CID_EXPOSURE:
280		if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0)
281			return -EIO;
282		break;
283	case V4L2_CID_DO_WHITE_BALANCE:
284		if ((ctrl->value = sn9c102_read_reg(cam, 0x02)) < 0)
285			return -EIO;
286		ctrl->value = (ctrl->value & 0x04) ? 1 : 0;
287		break;
288	case V4L2_CID_RED_BALANCE:
289		if ((ctrl->value = sn9c102_read_reg(cam, 0x05)) < 0)
290			return -EIO;
291		ctrl->value &= 0x7f;
292		break;
293	case V4L2_CID_BLUE_BALANCE:
294		if ((ctrl->value = sn9c102_read_reg(cam, 0x06)) < 0)
295			return -EIO;
296		ctrl->value &= 0x7f;
297		break;
298	case SN9C102_V4L2_CID_GREEN_BALANCE:
299		if ((ctrl->value = sn9c102_read_reg(cam, 0x07)) < 0)
300			return -EIO;
301		ctrl->value &= 0x7f;
302		break;
303	case SN9C102_V4L2_CID_BAND_FILTER:
304		if ((ctrl->value = sn9c102_i2c_read(cam, 0x3b)) < 0)
305			return -EIO;
306		ctrl->value &= 0x08;
307		break;
308	case V4L2_CID_GAIN:
309		if ((ctrl->value = sn9c102_i2c_read(cam, 0x00)) < 0)
310			return -EIO;
311		ctrl->value &= 0x1f;
312		break;
313	case V4L2_CID_AUTOGAIN:
314		if ((ctrl->value = sn9c102_i2c_read(cam, 0x13)) < 0)
315			return -EIO;
316		ctrl->value &= 0x01;
317		break;
318	default:
319		return -EINVAL;
320	}
321
322	return err ? -EIO : 0;
323}
324
325
326static int ov7660_set_ctrl(struct sn9c102_device* cam,
327			   const struct v4l2_control* ctrl)
328{
329	int err = 0;
330
331	switch (ctrl->id) {
332	case V4L2_CID_EXPOSURE:
333		err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
334		break;
335	case V4L2_CID_DO_WHITE_BALANCE:
336		err += sn9c102_write_reg(cam, 0x43 | (ctrl->value << 2), 0x02);
337		break;
338	case V4L2_CID_RED_BALANCE:
339		err += sn9c102_write_reg(cam, ctrl->value, 0x05);
340		break;
341	case V4L2_CID_BLUE_BALANCE:
342		err += sn9c102_write_reg(cam, ctrl->value, 0x06);
343		break;
344	case SN9C102_V4L2_CID_GREEN_BALANCE:
345		err += sn9c102_write_reg(cam, ctrl->value, 0x07);
346		break;
347	case SN9C102_V4L2_CID_BAND_FILTER:
348		err += sn9c102_i2c_write(cam, ctrl->value << 3, 0x3b);
349		break;
350	case V4L2_CID_GAIN:
351		err += sn9c102_i2c_write(cam, 0x00, 0x60 + ctrl->value);
352		break;
353	case V4L2_CID_AUTOGAIN:
354		err += sn9c102_i2c_write(cam, 0x13, 0xc0 |
355						    (ctrl->value * 0x07));
356		break;
357	default:
358		return -EINVAL;
359	}
360
361	return err ? -EIO : 0;
362}
363
364
365static int ov7660_set_crop(struct sn9c102_device* cam,
366			   const struct v4l2_rect* rect)
367{
368	struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
369	int err = 0;
370	u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1,
371	   v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
372
373	err += sn9c102_write_reg(cam, h_start, 0x12);
374	err += sn9c102_write_reg(cam, v_start, 0x13);
375
376	return err;
377}
378
379
380static int ov7660_set_pix_format(struct sn9c102_device* cam,
381				 const struct v4l2_pix_format* pix)
382{
383	int r0, err = 0;
384
385	r0 = sn9c102_pread_reg(cam, 0x01);
386
387	if (pix->pixelformat == V4L2_PIX_FMT_JPEG) {
388		err += sn9c102_write_reg(cam, r0 | 0x40, 0x01);
389		err += sn9c102_write_reg(cam, 0xa2, 0x17);
390		err += sn9c102_i2c_write(cam, 0x11, 0x00);
391	} else {
392		err += sn9c102_write_reg(cam, r0 | 0x40, 0x01);
393		err += sn9c102_write_reg(cam, 0xa2, 0x17);
394		err += sn9c102_i2c_write(cam, 0x11, 0x0d);
395	}
396
397	return err;
398}
399
400
401static const struct sn9c102_sensor ov7660 = {
402	.name = "OV7660",
403	.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
404	.supported_bridge = BRIDGE_SN9C105 | BRIDGE_SN9C120,
405	.sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
406	.frequency = SN9C102_I2C_100KHZ,
407	.interface = SN9C102_I2C_2WIRES,
408	.i2c_slave_id = 0x21,
409	.init = &ov7660_init,
410	.qctrl = {
411		{
412			.id = V4L2_CID_GAIN,
413			.type = V4L2_CTRL_TYPE_INTEGER,
414			.name = "global gain",
415			.minimum = 0x00,
416			.maximum = 0x1f,
417			.step = 0x01,
418			.default_value = 0x09,
419			.flags = 0,
420		},
421		{
422			.id = V4L2_CID_EXPOSURE,
423			.type = V4L2_CTRL_TYPE_INTEGER,
424			.name = "exposure",
425			.minimum = 0x00,
426			.maximum = 0xff,
427			.step = 0x01,
428			.default_value = 0x27,
429			.flags = 0,
430		},
431		{
432			.id = V4L2_CID_DO_WHITE_BALANCE,
433			.type = V4L2_CTRL_TYPE_BOOLEAN,
434			.name = "night mode",
435			.minimum = 0x00,
436			.maximum = 0x01,
437			.step = 0x01,
438			.default_value = 0x00,
439			.flags = 0,
440		},
441		{
442			.id = V4L2_CID_RED_BALANCE,
443			.type = V4L2_CTRL_TYPE_INTEGER,
444			.name = "red balance",
445			.minimum = 0x00,
446			.maximum = 0x7f,
447			.step = 0x01,
448			.default_value = 0x14,
449			.flags = 0,
450		},
451		{
452			.id = V4L2_CID_BLUE_BALANCE,
453			.type = V4L2_CTRL_TYPE_INTEGER,
454			.name = "blue balance",
455			.minimum = 0x00,
456			.maximum = 0x7f,
457			.step = 0x01,
458			.default_value = 0x14,
459			.flags = 0,
460		},
461		{
462			.id = V4L2_CID_AUTOGAIN,
463			.type = V4L2_CTRL_TYPE_BOOLEAN,
464			.name = "auto adjust",
465			.minimum = 0x00,
466			.maximum = 0x01,
467			.step = 0x01,
468			.default_value = 0x01,
469			.flags = 0,
470		},
471		{
472			.id = SN9C102_V4L2_CID_GREEN_BALANCE,
473			.type = V4L2_CTRL_TYPE_INTEGER,
474			.name = "green balance",
475			.minimum = 0x00,
476			.maximum = 0x7f,
477			.step = 0x01,
478			.default_value = 0x14,
479			.flags = 0,
480		},
481		{
482			.id = SN9C102_V4L2_CID_BAND_FILTER,
483			.type = V4L2_CTRL_TYPE_BOOLEAN,
484			.name = "band filter",
485			.minimum = 0x00,
486			.maximum = 0x01,
487			.step = 0x01,
488			.default_value = 0x00,
489			.flags = 0,
490		},
491	},
492	.get_ctrl = &ov7660_get_ctrl,
493	.set_ctrl = &ov7660_set_ctrl,
494	.cropcap = {
495		.bounds = {
496			.left = 0,
497			.top = 0,
498			.width = 640,
499			.height = 480,
500		},
501		.defrect = {
502			.left = 0,
503			.top = 0,
504			.width = 640,
505			.height = 480,
506		},
507	},
508	.set_crop = &ov7660_set_crop,
509	.pix_format = {
510		.width = 640,
511		.height = 480,
512		.pixelformat = V4L2_PIX_FMT_JPEG,
513		.priv = 8,
514	},
515	.set_pix_format = &ov7660_set_pix_format
516};
517
518
519int sn9c102_probe_ov7660(struct sn9c102_device* cam)
520{
521	int pid, ver, err;
522
523	err = sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1},
524				       {0x01, 0x01}, {0x00, 0x01},
525				       {0x28, 0x17});
526
527	pid = sn9c102_i2c_try_read(cam, &ov7660, 0x0a);
528	ver = sn9c102_i2c_try_read(cam, &ov7660, 0x0b);
529	if (err || pid < 0 || ver < 0)
530		return -EIO;
531	if (pid != 0x76 || ver != 0x60)
532		return -ENODEV;
533
534	sn9c102_attach_sensor(cam, &ov7660);
535
536	return 0;
537}
538