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