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