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