V4L/DVB (5474): SN9C1xx driver updates
[linux-2.6.git] / drivers / media / video / sn9c102 / sn9c102_hv7131r.c
1 /***************************************************************************
2  * Plug-in for HV7131R 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 int hv7131r_init(struct sn9c102_device* cam)
26 {
27         int err = 0;
28
29         switch (sn9c102_get_bridge(cam)) {
30         case BRIDGE_SN9C103:
31                 err += sn9c102_write_reg(cam, 0x00, 0x03);
32                 err += sn9c102_write_reg(cam, 0x1a, 0x04);
33                 err += sn9c102_write_reg(cam, 0x20, 0x05);
34                 err += sn9c102_write_reg(cam, 0x20, 0x06);
35                 err += sn9c102_write_reg(cam, 0x03, 0x10);
36                 err += sn9c102_write_reg(cam, 0x00, 0x14);
37                 err += sn9c102_write_reg(cam, 0x60, 0x17);
38                 err += sn9c102_write_reg(cam, 0x0a, 0x18);
39                 err += sn9c102_write_reg(cam, 0xf0, 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, 0x10, 0x21);
48                 err += sn9c102_write_reg(cam, 0x20, 0x22);
49                 err += sn9c102_write_reg(cam, 0x30, 0x23);
50                 err += sn9c102_write_reg(cam, 0x40, 0x24);
51                 err += sn9c102_write_reg(cam, 0x50, 0x25);
52                 err += sn9c102_write_reg(cam, 0x60, 0x26);
53                 err += sn9c102_write_reg(cam, 0x70, 0x27);
54                 err += sn9c102_write_reg(cam, 0x80, 0x28);
55                 err += sn9c102_write_reg(cam, 0x90, 0x29);
56                 err += sn9c102_write_reg(cam, 0xa0, 0x2a);
57                 err += sn9c102_write_reg(cam, 0xb0, 0x2b);
58                 err += sn9c102_write_reg(cam, 0xc0, 0x2c);
59                 err += sn9c102_write_reg(cam, 0xd0, 0x2d);
60                 err += sn9c102_write_reg(cam, 0xe0, 0x2e);
61                 err += sn9c102_write_reg(cam, 0xf0, 0x2f);
62                 err += sn9c102_write_reg(cam, 0xff, 0x30);
63                 break;
64         case BRIDGE_SN9C105:
65         case BRIDGE_SN9C120:
66                 err += sn9c102_write_reg(cam, 0x44, 0x01);
67                 err += sn9c102_write_reg(cam, 0x40, 0x02);
68                 err += sn9c102_write_reg(cam, 0x00, 0x03);
69                 err += sn9c102_write_reg(cam, 0x1a, 0x04);
70                 err += sn9c102_write_reg(cam, 0x44, 0x05);
71                 err += sn9c102_write_reg(cam, 0x3e, 0x06);
72                 err += sn9c102_write_reg(cam, 0x1a, 0x07);
73                 err += sn9c102_write_reg(cam, 0x03, 0x10);
74                 err += sn9c102_write_reg(cam, 0x08, 0x14);
75                 err += sn9c102_write_reg(cam, 0xa3, 0x17);
76                 err += sn9c102_write_reg(cam, 0x4b, 0x18);
77                 err += sn9c102_write_reg(cam, 0x00, 0x19);
78                 err += sn9c102_write_reg(cam, 0x1d, 0x1a);
79                 err += sn9c102_write_reg(cam, 0x10, 0x1b);
80                 err += sn9c102_write_reg(cam, 0x02, 0x1c);
81                 err += sn9c102_write_reg(cam, 0x03, 0x1d);
82                 err += sn9c102_write_reg(cam, 0x0f, 0x1e);
83                 err += sn9c102_write_reg(cam, 0x0c, 0x1f);
84                 err += sn9c102_write_reg(cam, 0x00, 0x20);
85                 err += sn9c102_write_reg(cam, 0x29, 0x21);
86                 err += sn9c102_write_reg(cam, 0x40, 0x22);
87                 err += sn9c102_write_reg(cam, 0x54, 0x23);
88                 err += sn9c102_write_reg(cam, 0x66, 0x24);
89                 err += sn9c102_write_reg(cam, 0x76, 0x25);
90                 err += sn9c102_write_reg(cam, 0x85, 0x26);
91                 err += sn9c102_write_reg(cam, 0x94, 0x27);
92                 err += sn9c102_write_reg(cam, 0xa1, 0x28);
93                 err += sn9c102_write_reg(cam, 0xae, 0x29);
94                 err += sn9c102_write_reg(cam, 0xbb, 0x2a);
95                 err += sn9c102_write_reg(cam, 0xc7, 0x2b);
96                 err += sn9c102_write_reg(cam, 0xd3, 0x2c);
97                 err += sn9c102_write_reg(cam, 0xde, 0x2d);
98                 err += sn9c102_write_reg(cam, 0xea, 0x2e);
99                 err += sn9c102_write_reg(cam, 0xf4, 0x2f);
100                 err += sn9c102_write_reg(cam, 0xff, 0x30);
101                 err += sn9c102_write_reg(cam, 0x00, 0x3F);
102                 err += sn9c102_write_reg(cam, 0xC7, 0x40);
103                 err += sn9c102_write_reg(cam, 0x01, 0x41);
104                 err += sn9c102_write_reg(cam, 0x44, 0x42);
105                 err += sn9c102_write_reg(cam, 0x00, 0x43);
106                 err += sn9c102_write_reg(cam, 0x44, 0x44);
107                 err += sn9c102_write_reg(cam, 0x00, 0x45);
108                 err += sn9c102_write_reg(cam, 0x44, 0x46);
109                 err += sn9c102_write_reg(cam, 0x00, 0x47);
110                 err += sn9c102_write_reg(cam, 0xC7, 0x48);
111                 err += sn9c102_write_reg(cam, 0x01, 0x49);
112                 err += sn9c102_write_reg(cam, 0xC7, 0x4A);
113                 err += sn9c102_write_reg(cam, 0x01, 0x4B);
114                 err += sn9c102_write_reg(cam, 0xC7, 0x4C);
115                 err += sn9c102_write_reg(cam, 0x01, 0x4D);
116                 err += sn9c102_write_reg(cam, 0x44, 0x4E);
117                 err += sn9c102_write_reg(cam, 0x00, 0x4F);
118                 err += sn9c102_write_reg(cam, 0x44, 0x50);
119                 err += sn9c102_write_reg(cam, 0x00, 0x51);
120                 err += sn9c102_write_reg(cam, 0x44, 0x52);
121                 err += sn9c102_write_reg(cam, 0x00, 0x53);
122                 err += sn9c102_write_reg(cam, 0xC7, 0x54);
123                 err += sn9c102_write_reg(cam, 0x01, 0x55);
124                 err += sn9c102_write_reg(cam, 0xC7, 0x56);
125                 err += sn9c102_write_reg(cam, 0x01, 0x57);
126                 err += sn9c102_write_reg(cam, 0xC7, 0x58);
127                 err += sn9c102_write_reg(cam, 0x01, 0x59);
128                 err += sn9c102_write_reg(cam, 0x44, 0x5A);
129                 err += sn9c102_write_reg(cam, 0x00, 0x5B);
130                 err += sn9c102_write_reg(cam, 0x44, 0x5C);
131                 err += sn9c102_write_reg(cam, 0x00, 0x5D);
132                 err += sn9c102_write_reg(cam, 0x44, 0x5E);
133                 err += sn9c102_write_reg(cam, 0x00, 0x5F);
134                 err += sn9c102_write_reg(cam, 0xC7, 0x60);
135                 err += sn9c102_write_reg(cam, 0x01, 0x61);
136                 err += sn9c102_write_reg(cam, 0xC7, 0x62);
137                 err += sn9c102_write_reg(cam, 0x01, 0x63);
138                 err += sn9c102_write_reg(cam, 0xC7, 0x64);
139                 err += sn9c102_write_reg(cam, 0x01, 0x65);
140                 err += sn9c102_write_reg(cam, 0x44, 0x66);
141                 err += sn9c102_write_reg(cam, 0x00, 0x67);
142                 err += sn9c102_write_reg(cam, 0x44, 0x68);
143                 err += sn9c102_write_reg(cam, 0x00, 0x69);
144                 err += sn9c102_write_reg(cam, 0x44, 0x6A);
145                 err += sn9c102_write_reg(cam, 0x00, 0x6B);
146                 err += sn9c102_write_reg(cam, 0xC7, 0x6C);
147                 err += sn9c102_write_reg(cam, 0x01, 0x6D);
148                 err += sn9c102_write_reg(cam, 0xC7, 0x6E);
149                 err += sn9c102_write_reg(cam, 0x01, 0x6F);
150                 err += sn9c102_write_reg(cam, 0xC7, 0x70);
151                 err += sn9c102_write_reg(cam, 0x01, 0x71);
152                 err += sn9c102_write_reg(cam, 0x44, 0x72);
153                 err += sn9c102_write_reg(cam, 0x00, 0x73);
154                 err += sn9c102_write_reg(cam, 0x44, 0x74);
155                 err += sn9c102_write_reg(cam, 0x00, 0x75);
156                 err += sn9c102_write_reg(cam, 0x44, 0x76);
157                 err += sn9c102_write_reg(cam, 0x00, 0x77);
158                 err += sn9c102_write_reg(cam, 0xC7, 0x78);
159                 err += sn9c102_write_reg(cam, 0x01, 0x79);
160                 err += sn9c102_write_reg(cam, 0xC7, 0x7A);
161                 err += sn9c102_write_reg(cam, 0x01, 0x7B);
162                 err += sn9c102_write_reg(cam, 0xC7, 0x7C);
163                 err += sn9c102_write_reg(cam, 0x01, 0x7D);
164                 err += sn9c102_write_reg(cam, 0x44, 0x7E);
165                 err += sn9c102_write_reg(cam, 0x00, 0x7F);
166                 err += sn9c102_write_reg(cam, 0x14, 0x84);
167                 err += sn9c102_write_reg(cam, 0x00, 0x85);
168                 err += sn9c102_write_reg(cam, 0x27, 0x86);
169                 err += sn9c102_write_reg(cam, 0x00, 0x87);
170                 err += sn9c102_write_reg(cam, 0x07, 0x88);
171                 err += sn9c102_write_reg(cam, 0x00, 0x89);
172                 err += sn9c102_write_reg(cam, 0xEC, 0x8A);
173                 err += sn9c102_write_reg(cam, 0x0f, 0x8B);
174                 err += sn9c102_write_reg(cam, 0xD8, 0x8C);
175                 err += sn9c102_write_reg(cam, 0x0f, 0x8D);
176                 err += sn9c102_write_reg(cam, 0x3D, 0x8E);
177                 err += sn9c102_write_reg(cam, 0x00, 0x8F);
178                 err += sn9c102_write_reg(cam, 0x3D, 0x90);
179                 err += sn9c102_write_reg(cam, 0x00, 0x91);
180                 err += sn9c102_write_reg(cam, 0xCD, 0x92);
181                 err += sn9c102_write_reg(cam, 0x0f, 0x93);
182                 err += sn9c102_write_reg(cam, 0xf7, 0x94);
183                 err += sn9c102_write_reg(cam, 0x0f, 0x95);
184                 err += sn9c102_write_reg(cam, 0x0C, 0x96);
185                 err += sn9c102_write_reg(cam, 0x00, 0x97);
186                 err += sn9c102_write_reg(cam, 0x00, 0x98);
187                 err += sn9c102_write_reg(cam, 0x66, 0x99);
188                 err += sn9c102_write_reg(cam, 0x05, 0x9A);
189                 err += sn9c102_write_reg(cam, 0x00, 0x9B);
190                 err += sn9c102_write_reg(cam, 0x04, 0x9C);
191                 err += sn9c102_write_reg(cam, 0x00, 0x9D);
192                 err += sn9c102_write_reg(cam, 0x08, 0x9E);
193                 err += sn9c102_write_reg(cam, 0x00, 0x9F);
194                 err += sn9c102_write_reg(cam, 0x2D, 0xC0);
195                 err += sn9c102_write_reg(cam, 0x2D, 0xC1);
196                 err += sn9c102_write_reg(cam, 0x3A, 0xC2);
197                 err += sn9c102_write_reg(cam, 0x05, 0xC3);
198                 err += sn9c102_write_reg(cam, 0x04, 0xC4);
199                 err += sn9c102_write_reg(cam, 0x3F, 0xC5);
200                 err += sn9c102_write_reg(cam, 0x00, 0xC6);
201                 err += sn9c102_write_reg(cam, 0x00, 0xC7);
202                 err += sn9c102_write_reg(cam, 0x50, 0xC8);
203                 err += sn9c102_write_reg(cam, 0x3C, 0xC9);
204                 err += sn9c102_write_reg(cam, 0x28, 0xCA);
205                 err += sn9c102_write_reg(cam, 0xD8, 0xCB);
206                 err += sn9c102_write_reg(cam, 0x14, 0xCC);
207                 err += sn9c102_write_reg(cam, 0xEC, 0xCD);
208                 err += sn9c102_write_reg(cam, 0x32, 0xCE);
209                 err += sn9c102_write_reg(cam, 0xDD, 0xCF);
210                 err += sn9c102_write_reg(cam, 0x32, 0xD0);
211                 err += sn9c102_write_reg(cam, 0xDD, 0xD1);
212                 err += sn9c102_write_reg(cam, 0x6A, 0xD2);
213                 err += sn9c102_write_reg(cam, 0x50, 0xD3);
214                 err += sn9c102_write_reg(cam, 0x00, 0xD4);
215                 err += sn9c102_write_reg(cam, 0x00, 0xD5);
216                 err += sn9c102_write_reg(cam, 0x00, 0xD6);
217                 break;
218         default:
219                 break;
220         }
221
222         err += sn9c102_i2c_write(cam, 0x20, 0x00);
223         err += sn9c102_i2c_write(cam, 0x21, 0xd6);
224         err += sn9c102_i2c_write(cam, 0x25, 0x06);
225
226         return err;
227 }
228
229
230 static int hv7131r_get_ctrl(struct sn9c102_device* cam,
231                             struct v4l2_control* ctrl)
232 {
233         switch (ctrl->id) {
234         case V4L2_CID_GAIN:
235                 if ((ctrl->value = sn9c102_i2c_read(cam, 0x30)) < 0)
236                         return -EIO;
237                 return 0;
238         case V4L2_CID_RED_BALANCE:
239                 if ((ctrl->value = sn9c102_i2c_read(cam, 0x31)) < 0)
240                         return -EIO;
241                 ctrl->value = ctrl->value & 0x3f;
242                 return 0;
243         case V4L2_CID_BLUE_BALANCE:
244                 if ((ctrl->value = sn9c102_i2c_read(cam, 0x33)) < 0)
245                         return -EIO;
246                 ctrl->value = ctrl->value & 0x3f;
247                 return 0;
248         case SN9C102_V4L2_CID_GREEN_BALANCE:
249                 if ((ctrl->value = sn9c102_i2c_read(cam, 0x32)) < 0)
250                         return -EIO;
251                 ctrl->value = ctrl->value & 0x3f;
252                 return 0;
253         case V4L2_CID_BLACK_LEVEL:
254                 if ((ctrl->value = sn9c102_i2c_read(cam, 0x01)) < 0)
255                         return -EIO;
256                 ctrl->value = (ctrl->value & 0x08) ? 1 : 0;
257                 return 0;
258         default:
259                 return -EINVAL;
260         }
261 }
262
263
264 static int hv7131r_set_ctrl(struct sn9c102_device* cam,
265                             const struct v4l2_control* ctrl)
266 {
267         int err = 0;
268
269         switch (ctrl->id) {
270         case V4L2_CID_GAIN:
271                 err += sn9c102_i2c_write(cam, 0x30, ctrl->value);
272                 break;
273         case V4L2_CID_RED_BALANCE:
274                 err += sn9c102_i2c_write(cam, 0x31, ctrl->value);
275                 break;
276         case V4L2_CID_BLUE_BALANCE:
277                 err += sn9c102_i2c_write(cam, 0x33, ctrl->value);
278                 break;
279         case SN9C102_V4L2_CID_GREEN_BALANCE:
280                 err += sn9c102_i2c_write(cam, 0x32, ctrl->value);
281                 break;
282         case V4L2_CID_BLACK_LEVEL:
283                 {
284                         int r = sn9c102_i2c_read(cam, 0x01);
285                         if (r < 0)
286                                 return -EIO;
287                         err += sn9c102_i2c_write(cam, 0x01,
288                                                  (ctrl->value<<3) | (r&0xf7));
289                 }
290                 break;
291         default:
292                 return -EINVAL;
293         }
294
295         return err ? -EIO : 0;
296 }
297
298
299 static int hv7131r_set_crop(struct sn9c102_device* cam,
300                             const struct v4l2_rect* rect)
301 {
302         struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
303         int err = 0;
304         u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1,
305            v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
306
307         err += sn9c102_write_reg(cam, h_start, 0x12);
308         err += sn9c102_write_reg(cam, v_start, 0x13);
309
310         return err;
311 }
312
313
314 static int hv7131r_set_pix_format(struct sn9c102_device* cam,
315                                   const struct v4l2_pix_format* pix)
316 {
317         int err = 0;
318
319         switch (sn9c102_get_bridge(cam)) {
320         case BRIDGE_SN9C103:
321                 if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) {
322                         err += sn9c102_write_reg(cam, 0xa0, 0x19);
323                         err += sn9c102_i2c_write(cam, 0x01, 0x04);
324                 } else {
325                         err += sn9c102_write_reg(cam, 0x30, 0x19);
326                         err += sn9c102_i2c_write(cam, 0x01, 0x04);
327                 }
328                 break;
329         case BRIDGE_SN9C105:
330         case BRIDGE_SN9C120:
331                 if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) {
332                         err += sn9c102_write_reg(cam, 0xa5, 0x17);
333                         err += sn9c102_i2c_write(cam, 0x01, 0x24);
334                 } else {
335                         err += sn9c102_write_reg(cam, 0xa3, 0x17);
336                         err += sn9c102_i2c_write(cam, 0x01, 0x04);
337                 }
338                 break;
339         default:
340                 break;
341         }
342
343         return err;
344 }
345
346
347 static struct sn9c102_sensor hv7131r = {
348         .name = "HV7131R",
349         .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
350         .supported_bridge = BRIDGE_SN9C103 | BRIDGE_SN9C105 | BRIDGE_SN9C120,
351         .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
352         .frequency = SN9C102_I2C_100KHZ,
353         .interface = SN9C102_I2C_2WIRES,
354         .i2c_slave_id = 0x11,
355         .init = &hv7131r_init,
356         .qctrl = {
357                 {
358                         .id = V4L2_CID_GAIN,
359                         .type = V4L2_CTRL_TYPE_INTEGER,
360                         .name = "global gain",
361                         .minimum = 0x00,
362                         .maximum = 0xff,
363                         .step = 0x01,
364                         .default_value = 0x40,
365                         .flags = 0,
366                 },
367                 {
368                         .id = V4L2_CID_RED_BALANCE,
369                         .type = V4L2_CTRL_TYPE_INTEGER,
370                         .name = "red balance",
371                         .minimum = 0x00,
372                         .maximum = 0x3f,
373                         .step = 0x01,
374                         .default_value = 0x08,
375                         .flags = 0,
376                 },
377                 {
378                         .id = V4L2_CID_BLUE_BALANCE,
379                         .type = V4L2_CTRL_TYPE_INTEGER,
380                         .name = "blue balance",
381                         .minimum = 0x00,
382                         .maximum = 0x3f,
383                         .step = 0x01,
384                         .default_value = 0x1a,
385                         .flags = 0,
386                 },
387                 {
388                         .id = SN9C102_V4L2_CID_GREEN_BALANCE,
389                         .type = V4L2_CTRL_TYPE_INTEGER,
390                         .name = "green balance",
391                         .minimum = 0x00,
392                         .maximum = 0x3f,
393                         .step = 0x01,
394                         .default_value = 0x2f,
395                         .flags = 0,
396                 },
397                 {
398                         .id = V4L2_CID_BLACK_LEVEL,
399                         .type = V4L2_CTRL_TYPE_BOOLEAN,
400                         .name = "auto black level compensation",
401                         .minimum = 0x00,
402                         .maximum = 0x01,
403                         .step = 0x01,
404                         .default_value = 0x00,
405                         .flags = 0,
406                 },
407         },
408         .get_ctrl = &hv7131r_get_ctrl,
409         .set_ctrl = &hv7131r_set_ctrl,
410         .cropcap = {
411                 .bounds = {
412                         .left = 0,
413                         .top = 0,
414                         .width = 640,
415                         .height = 480,
416                 },
417                 .defrect = {
418                         .left = 0,
419                         .top = 0,
420                         .width = 640,
421                         .height = 480,
422                 },
423         },
424         .set_crop = &hv7131r_set_crop,
425         .pix_format = {
426                 .width = 640,
427                 .height = 480,
428                 .pixelformat = V4L2_PIX_FMT_SBGGR8,
429                 .priv = 8,
430         },
431         .set_pix_format = &hv7131r_set_pix_format
432 };
433
434
435 int sn9c102_probe_hv7131r(struct sn9c102_device* cam)
436 {
437         int devid, err = 0;
438
439         err += sn9c102_write_reg(cam, 0x09, 0x01);
440         err += sn9c102_write_reg(cam, 0x44, 0x02);
441         err += sn9c102_write_reg(cam, 0x34, 0x01);
442         err += sn9c102_write_reg(cam, 0x20, 0x17);
443         err += sn9c102_write_reg(cam, 0x34, 0x01);
444         err += sn9c102_write_reg(cam, 0x46, 0x01);
445         if (err)
446                 return -EIO;
447
448         devid = sn9c102_i2c_try_read(cam, &hv7131r, 0x00);
449         if (devid < 0)
450                 return -EIO;
451
452         if (devid != 0x02)
453                 return -ENODEV;
454
455         sn9c102_attach_sensor(cam, &hv7131r);
456
457         return 0;
458 }