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