a33d1bc10f90e536e10f68c3f9f9392998725f69
[linux-2.6.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 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 = sn9c102_get_sensor(cam);
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         .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
241         .frequency = SN9C102_I2C_100KHZ,
242         .interface = SN9C102_I2C_2WIRES,
243         .i2c_slave_id = 0x5d,
244         .init = &mi0343_init,
245         .qctrl = {
246                 {
247                         .id = V4L2_CID_EXPOSURE,
248                         .type = V4L2_CTRL_TYPE_INTEGER,
249                         .name = "exposure",
250                         .minimum = 0x00,
251                         .maximum = 0x0f,
252                         .step = 0x01,
253                         .default_value = 0x06,
254                         .flags = 0,
255                 },
256                 {
257                         .id = V4L2_CID_GAIN,
258                         .type = V4L2_CTRL_TYPE_INTEGER,
259                         .name = "global gain",
260                         .minimum = 0x00,
261                         .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0),/*0x6d*/
262                         .step = 0x01,
263                         .default_value = 0x00,
264                         .flags = 0,
265                 },
266                 {
267                         .id = V4L2_CID_HFLIP,
268                         .type = V4L2_CTRL_TYPE_BOOLEAN,
269                         .name = "horizontal mirror",
270                         .minimum = 0,
271                         .maximum = 1,
272                         .step = 1,
273                         .default_value = 0,
274                         .flags = 0,
275                 },
276                 {
277                         .id = V4L2_CID_VFLIP,
278                         .type = V4L2_CTRL_TYPE_BOOLEAN,
279                         .name = "vertical mirror",
280                         .minimum = 0,
281                         .maximum = 1,
282                         .step = 1,
283                         .default_value = 0,
284                         .flags = 0,
285                 },
286                 {
287                         .id = V4L2_CID_RED_BALANCE,
288                         .type = V4L2_CTRL_TYPE_INTEGER,
289                         .name = "red balance",
290                         .minimum = 0x00,
291                         .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0),
292                         .step = 0x01,
293                         .default_value = 0x00,
294                         .flags = 0,
295                 },
296                 {
297                         .id = V4L2_CID_BLUE_BALANCE,
298                         .type = V4L2_CTRL_TYPE_INTEGER,
299                         .name = "blue balance",
300                         .minimum = 0x00,
301                         .maximum = (0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0),
302                         .step = 0x01,
303                         .default_value = 0x00,
304                         .flags = 0,
305                 },
306                 {
307                         .id = SN9C102_V4L2_CID_GREEN_BALANCE,
308                         .type = V4L2_CTRL_TYPE_INTEGER,
309                         .name = "green balance",
310                         .minimum = 0x00,
311                         .maximum = ((0x3f-0x10)+(0x7f-0x60)+(0xff-0xe0)),
312                         .step = 0x01,
313                         .default_value = 0x00,
314                         .flags = 0,
315                 },
316         },
317         .get_ctrl = &mi0343_get_ctrl,
318         .set_ctrl = &mi0343_set_ctrl,
319         .cropcap = {
320                 .bounds = {
321                         .left = 0,
322                         .top = 0,
323                         .width = 640,
324                         .height = 480,
325                 },
326                 .defrect = {
327                         .left = 0,
328                         .top = 0,
329                         .width = 640,
330                         .height = 480,
331                 },
332         },
333         .set_crop = &mi0343_set_crop,
334         .pix_format = {
335                 .width = 640,
336                 .height = 480,
337                 .pixelformat = V4L2_PIX_FMT_SBGGR8,
338                 .priv = 8,
339         },
340         .set_pix_format = &mi0343_set_pix_format
341 };
342
343
344 int sn9c102_probe_mi0343(struct sn9c102_device* cam)
345 {
346         int err = 0;
347
348         err += sn9c102_write_reg(cam, 0x01, 0x01);
349         err += sn9c102_write_reg(cam, 0x00, 0x01);
350         err += sn9c102_write_reg(cam, 0x28, 0x17);
351         if (err)
352                 return -EIO;
353
354         if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, 0x00,
355                                      2, mi0343_i2c_data) < 0)
356                 return -EIO;
357
358         if (mi0343_i2c_data[4] != 0x32 && mi0343_i2c_data[3] != 0xe3)
359                 return -ENODEV;
360
361         sn9c102_attach_sensor(cam, &mi0343);
362
363         return 0;
364 }