USB: pwc-if loop fix
[linux-2.6] / drivers / media / video / sn9c102 / sn9c102_mi0343.c
1 /***************************************************************************
2  * Plug-in for MI-0343 image sensor connected to the SN9C10x PC Camera     *
3  * Controllers                                                             *
4  *                                                                         *
5  * Copyright (C) 2004-2006 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 mi0343;
26 static u8 mi0343_i2c_data[5+1];
27
28
29 static int mi0343_init(struct sn9c102_device* cam)
30 {
31         int err = 0;
32
33         err += sn9c102_write_reg(cam, 0x00, 0x10);
34         err += sn9c102_write_reg(cam, 0x00, 0x11);
35         err += sn9c102_write_reg(cam, 0x0a, 0x14);
36         err += sn9c102_write_reg(cam, 0x40, 0x01);
37         err += sn9c102_write_reg(cam, 0x20, 0x17);
38         err += sn9c102_write_reg(cam, 0x07, 0x18);
39         err += sn9c102_write_reg(cam, 0xa0, 0x19);
40
41         err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
42                                          0x0d, 0x00, 0x01, 0, 0);
43         err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
44                                          0x0d, 0x00, 0x00, 0, 0);
45         err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
46                                          0x03, 0x01, 0xe1, 0, 0);
47         err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
48                                          0x04, 0x02, 0x81, 0, 0);
49         err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
50                                          0x05, 0x00, 0x17, 0, 0);
51         err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
52                                          0x06, 0x00, 0x11, 0, 0);
53         err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
54                                          0x62, 0x04, 0x9a, 0, 0);
55
56         return err;
57 }
58
59
60 static int mi0343_get_ctrl(struct sn9c102_device* cam,
61                            struct v4l2_control* ctrl)
62 {
63         switch (ctrl->id) {
64         case V4L2_CID_EXPOSURE:
65                 if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
66                                              0x09, 2+1, mi0343_i2c_data) < 0)
67                         return -EIO;
68                 ctrl->value = mi0343_i2c_data[2];
69                 return 0;
70         case V4L2_CID_GAIN:
71                 if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
72                                              0x35, 2+1, mi0343_i2c_data) < 0)
73                         return -EIO;
74                 break;
75         case V4L2_CID_HFLIP:
76                 if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
77                                              0x20, 2+1, mi0343_i2c_data) < 0)
78                         return -EIO;
79                 ctrl->value = mi0343_i2c_data[3] & 0x20 ? 1 : 0;
80                 return 0;
81         case V4L2_CID_VFLIP:
82                 if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
83                                              0x20, 2+1, mi0343_i2c_data) < 0)
84                         return -EIO;
85                 ctrl->value = mi0343_i2c_data[3] & 0x80 ? 1 : 0;
86                 return 0;
87         case V4L2_CID_RED_BALANCE:
88                 if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
89                                              0x2d, 2+1, mi0343_i2c_data) < 0)
90                         return -EIO;
91                 break;
92         case V4L2_CID_BLUE_BALANCE:
93                 if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
94                                              0x2c, 2+1, mi0343_i2c_data) < 0)
95                         return -EIO;
96                 break;
97         case SN9C102_V4L2_CID_GREEN_BALANCE:
98                 if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
99                                              0x2e, 2+1, mi0343_i2c_data) < 0)
100                         return -EIO;
101                 break;
102         default:
103                 return -EINVAL;
104         }
105
106         switch (ctrl->id) {
107         case V4L2_CID_GAIN:
108         case V4L2_CID_RED_BALANCE:
109         case V4L2_CID_BLUE_BALANCE:
110         case SN9C102_V4L2_CID_GREEN_BALANCE:
111                 ctrl->value = mi0343_i2c_data[3] | (mi0343_i2c_data[2] << 8);
112                 if (ctrl->value >= 0x10 && ctrl->value <= 0x3f)
113                         ctrl->value -= 0x10;
114                 else if (ctrl->value >= 0x60 && ctrl->value <= 0x7f)
115                         ctrl->value -= 0x60;
116                 else if (ctrl->value >= 0xe0 && ctrl->value <= 0xff)
117                         ctrl->value -= 0xe0;
118         }
119
120         return 0;
121 }
122
123
124 static int mi0343_set_ctrl(struct sn9c102_device* cam,
125                            const struct v4l2_control* ctrl)
126 {
127         u16 reg = 0;
128         int err = 0;
129
130         switch (ctrl->id) {
131         case V4L2_CID_GAIN:
132         case V4L2_CID_RED_BALANCE:
133         case V4L2_CID_BLUE_BALANCE:
134         case SN9C102_V4L2_CID_GREEN_BALANCE:
135                 if (ctrl->value <= (0x3f-0x10))
136                         reg = 0x10 + ctrl->value;
137                 else if (ctrl->value <= ((0x3f-0x10) + (0x7f-0x60)))
138                         reg = 0x60 + (ctrl->value - (0x3f-0x10));
139                 else
140                         reg = 0xe0 + (ctrl->value - (0x3f-0x10) - (0x7f-0x60));
141                 break;
142         }
143
144         switch (ctrl->id) {
145         case V4L2_CID_EXPOSURE:
146                 err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
147                                                  mi0343.i2c_slave_id,
148                                                  0x09, ctrl->value, 0x00,
149                                                  0, 0);
150                 break;
151         case V4L2_CID_GAIN:
152                 err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
153                                                  mi0343.i2c_slave_id,
154                                                  0x35, reg >> 8, reg & 0xff,
155                                                  0, 0);
156                 break;
157         case V4L2_CID_HFLIP:
158                 err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
159                                                  mi0343.i2c_slave_id,
160                                                  0x20, ctrl->value ? 0x40:0x00,
161                                                  ctrl->value ? 0x20:0x00,
162                                                  0, 0);
163                 break;
164         case V4L2_CID_VFLIP:
165                 err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
166                                                  mi0343.i2c_slave_id,
167                                                  0x20, ctrl->value ? 0x80:0x00,
168                                                  ctrl->value ? 0x80:0x00,
169                                                  0, 0);
170                 break;
171         case V4L2_CID_RED_BALANCE:
172                 err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
173                                                  mi0343.i2c_slave_id,
174                                                  0x2d, reg >> 8, reg & 0xff,
175                                                  0, 0);
176                 break;
177         case V4L2_CID_BLUE_BALANCE:
178                 err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
179                                                  mi0343.i2c_slave_id,
180                                                  0x2c, reg >> 8, reg & 0xff,
181                                                  0, 0);
182                 break;
183         case SN9C102_V4L2_CID_GREEN_BALANCE:
184                 err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
185                                                  mi0343.i2c_slave_id,
186                                                  0x2b, reg >> 8, reg & 0xff,
187                                                  0, 0);
188                 err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
189                                                  mi0343.i2c_slave_id,
190                                                  0x2e, reg >> 8, reg & 0xff,
191                                                  0, 0);
192                 break;
193         default:
194                 return -EINVAL;
195         }
196
197         return err ? -EIO : 0;
198 }
199
200
201 static int mi0343_set_crop(struct sn9c102_device* cam,
202                             const struct v4l2_rect* rect)
203 {
204         struct sn9c102_sensor* s = &mi0343;
205         int err = 0;
206         u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 0,
207            v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2;
208
209         err += sn9c102_write_reg(cam, h_start, 0x12);
210         err += sn9c102_write_reg(cam, v_start, 0x13);
211
212         return err;
213 }
214
215
216 static int mi0343_set_pix_format(struct sn9c102_device* cam,
217                                  const struct v4l2_pix_format* pix)
218 {
219         int err = 0;
220
221         if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) {
222                 err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
223                                                  mi0343.i2c_slave_id,
224                                                  0x0a, 0x00, 0x03, 0, 0);
225                 err += sn9c102_write_reg(cam, 0x20, 0x19);
226         } else {
227                 err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
228                                                  mi0343.i2c_slave_id,
229                                                  0x0a, 0x00, 0x05, 0, 0);
230                 err += sn9c102_write_reg(cam, 0xa0, 0x19);
231         }
232
233         return err;
234 }
235
236
237 static struct sn9c102_sensor mi0343 = {
238         .name = "MI-0343",
239         .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
240         .frequency = SN9C102_I2C_100KHZ,
241         .interface = SN9C102_I2C_2WIRES,
242         .i2c_slave_id = 0x5d,
243         .init = &mi0343_init,
244         .qctrl = {
245                 {
246                         .id = V4L2_CID_EXPOSURE,
247                         .type = V4L2_CTRL_TYPE_INTEGER,
248                         .name = "exposure",
249                         .minimum = 0x00,
250                         .maximum = 0x0f,
251                         .step = 0x01,
252                         .default_value = 0x06,
253                         .flags = 0,
254                 },
255                 {
256                         .id = V4L2_CID_GAIN,
257                         .type = V4L2_CTRL_TYPE_INTEGER,
258                         .name = "global gain",
259                         .minimum = 0x00,
260                         .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0),/*0x6d*/
261                         .step = 0x01,
262                         .default_value = 0x00,
263                         .flags = 0,
264                 },
265                 {
266                         .id = V4L2_CID_HFLIP,
267                         .type = V4L2_CTRL_TYPE_BOOLEAN,
268                         .name = "horizontal mirror",
269                         .minimum = 0,
270                         .maximum = 1,
271                         .step = 1,
272                         .default_value = 0,
273                         .flags = 0,
274                 },
275                 {
276                         .id = V4L2_CID_VFLIP,
277                         .type = V4L2_CTRL_TYPE_BOOLEAN,
278                         .name = "vertical mirror",
279                         .minimum = 0,
280                         .maximum = 1,
281                         .step = 1,
282                         .default_value = 0,
283                         .flags = 0,
284                 },
285                 {
286                         .id = V4L2_CID_RED_BALANCE,
287                         .type = V4L2_CTRL_TYPE_INTEGER,
288                         .name = "red balance",
289                         .minimum = 0x00,
290                         .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0),
291                         .step = 0x01,
292                         .default_value = 0x00,
293                         .flags = 0,
294                 },
295                 {
296                         .id = V4L2_CID_BLUE_BALANCE,
297                         .type = V4L2_CTRL_TYPE_INTEGER,
298                         .name = "blue balance",
299                         .minimum = 0x00,
300                         .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0),
301                         .step = 0x01,
302                         .default_value = 0x00,
303                         .flags = 0,
304                 },
305                 {
306                         .id = SN9C102_V4L2_CID_GREEN_BALANCE,
307                         .type = V4L2_CTRL_TYPE_INTEGER,
308                         .name = "green balance",
309                         .minimum = 0x00,
310                         .maximum = ((0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0)),
311                         .step = 0x01,
312                         .default_value = 0x00,
313                         .flags = 0,
314                 },
315         },
316         .get_ctrl = &mi0343_get_ctrl,
317         .set_ctrl = &mi0343_set_ctrl,
318         .cropcap = {
319                 .bounds = {
320                         .left = 0,
321                         .top = 0,
322                         .width = 640,
323                         .height = 480,
324                 },
325                 .defrect = {
326                         .left = 0,
327                         .top = 0,
328                         .width = 640,
329                         .height = 480,
330                 },
331         },
332         .set_crop = &mi0343_set_crop,
333         .pix_format = {
334                 .width = 640,
335                 .height = 480,
336                 .pixelformat = V4L2_PIX_FMT_SBGGR8,
337                 .priv = 8,
338         },
339         .set_pix_format = &mi0343_set_pix_format
340 };
341
342
343 int sn9c102_probe_mi0343(struct sn9c102_device* cam)
344 {
345         int err = 0;
346
347         err += sn9c102_write_reg(cam, 0x01, 0x01);
348         err += sn9c102_write_reg(cam, 0x00, 0x01);
349         err += sn9c102_write_reg(cam, 0x28, 0x17);
350         if (err)
351                 return -EIO;
352
353         if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, 0x00,
354                                      2, mi0343_i2c_data) < 0)
355                 return -EIO;
356
357         if (mi0343_i2c_data[4] != 0x32 && mi0343_i2c_data[3] != 0xe3)
358                 return -ENODEV;
359
360         sn9c102_attach_sensor(cam, &mi0343);
361
362         return 0;
363 }