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