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