V4L/DVB (9760): em28xx: move gpio lines into board table description
[linux-2.6] / drivers / media / video / zc0301 / zc0301_pas202bcb.c
1 /***************************************************************************
2  * Plug-in for PAS202BCB image sensor connected to the ZC0301 Image        *
3  * Processor and Control Chip                                              *
4  *                                                                         *
5  * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it>  *
6  *                                                                         *
7  * Initialization values of the ZC0301[P] have been taken from the SPCA5XX *
8  * driver maintained by Michel Xhaard <mxhaard@magic.fr>                   *
9  *                                                                         *
10  * This program is free software; you can redistribute it and/or modify    *
11  * it under the terms of the GNU General Public License as published by    *
12  * the Free Software Foundation; either version 2 of the License, or       *
13  * (at your option) any later version.                                     *
14  *                                                                         *
15  * This program is distributed in the hope that it will be useful,         *
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
18  * GNU General Public License for more details.                            *
19  *                                                                         *
20  * You should have received a copy of the GNU General Public License       *
21  * along with this program; if not, write to the Free Software             *
22  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
23  ***************************************************************************/
24
25 /*
26    NOTE: Sensor controls are disabled for now, becouse changing them while
27          streaming sometimes results in out-of-sync video frames. We'll use
28          the default initialization, until we know how to stop and start video
29          in the chip. However, the image quality still looks good under various
30          light conditions.
31 */
32
33 #include <linux/delay.h>
34 #include "zc0301_sensor.h"
35
36
37 static struct zc0301_sensor pas202bcb;
38
39
40 static int pas202bcb_init(struct zc0301_device* cam)
41 {
42         int err = 0;
43
44         err += zc0301_write_reg(cam, 0x0002, 0x00);
45         err += zc0301_write_reg(cam, 0x0003, 0x02);
46         err += zc0301_write_reg(cam, 0x0004, 0x80);
47         err += zc0301_write_reg(cam, 0x0005, 0x01);
48         err += zc0301_write_reg(cam, 0x0006, 0xE0);
49         err += zc0301_write_reg(cam, 0x0098, 0x00);
50         err += zc0301_write_reg(cam, 0x009A, 0x03);
51         err += zc0301_write_reg(cam, 0x011A, 0x00);
52         err += zc0301_write_reg(cam, 0x011C, 0x03);
53         err += zc0301_write_reg(cam, 0x009B, 0x01);
54         err += zc0301_write_reg(cam, 0x009C, 0xE6);
55         err += zc0301_write_reg(cam, 0x009D, 0x02);
56         err += zc0301_write_reg(cam, 0x009E, 0x86);
57
58         err += zc0301_i2c_write(cam, 0x02, 0x02);
59         err += zc0301_i2c_write(cam, 0x0A, 0x01);
60         err += zc0301_i2c_write(cam, 0x0B, 0x01);
61         err += zc0301_i2c_write(cam, 0x0D, 0x00);
62         err += zc0301_i2c_write(cam, 0x12, 0x05);
63         err += zc0301_i2c_write(cam, 0x13, 0x63);
64         err += zc0301_i2c_write(cam, 0x15, 0x70);
65
66         err += zc0301_write_reg(cam, 0x0101, 0xB7);
67         err += zc0301_write_reg(cam, 0x0100, 0x0D);
68         err += zc0301_write_reg(cam, 0x0189, 0x06);
69         err += zc0301_write_reg(cam, 0x01AD, 0x00);
70         err += zc0301_write_reg(cam, 0x01C5, 0x03);
71         err += zc0301_write_reg(cam, 0x01CB, 0x13);
72         err += zc0301_write_reg(cam, 0x0250, 0x08);
73         err += zc0301_write_reg(cam, 0x0301, 0x08);
74         err += zc0301_write_reg(cam, 0x018D, 0x70);
75         err += zc0301_write_reg(cam, 0x0008, 0x03);
76         err += zc0301_write_reg(cam, 0x01C6, 0x04);
77         err += zc0301_write_reg(cam, 0x01CB, 0x07);
78         err += zc0301_write_reg(cam, 0x0120, 0x11);
79         err += zc0301_write_reg(cam, 0x0121, 0x37);
80         err += zc0301_write_reg(cam, 0x0122, 0x58);
81         err += zc0301_write_reg(cam, 0x0123, 0x79);
82         err += zc0301_write_reg(cam, 0x0124, 0x91);
83         err += zc0301_write_reg(cam, 0x0125, 0xA6);
84         err += zc0301_write_reg(cam, 0x0126, 0xB8);
85         err += zc0301_write_reg(cam, 0x0127, 0xC7);
86         err += zc0301_write_reg(cam, 0x0128, 0xD3);
87         err += zc0301_write_reg(cam, 0x0129, 0xDE);
88         err += zc0301_write_reg(cam, 0x012A, 0xE6);
89         err += zc0301_write_reg(cam, 0x012B, 0xED);
90         err += zc0301_write_reg(cam, 0x012C, 0xF3);
91         err += zc0301_write_reg(cam, 0x012D, 0xF8);
92         err += zc0301_write_reg(cam, 0x012E, 0xFB);
93         err += zc0301_write_reg(cam, 0x012F, 0xFF);
94         err += zc0301_write_reg(cam, 0x0130, 0x26);
95         err += zc0301_write_reg(cam, 0x0131, 0x23);
96         err += zc0301_write_reg(cam, 0x0132, 0x20);
97         err += zc0301_write_reg(cam, 0x0133, 0x1C);
98         err += zc0301_write_reg(cam, 0x0134, 0x16);
99         err += zc0301_write_reg(cam, 0x0135, 0x13);
100         err += zc0301_write_reg(cam, 0x0136, 0x10);
101         err += zc0301_write_reg(cam, 0x0137, 0x0D);
102         err += zc0301_write_reg(cam, 0x0138, 0x0B);
103         err += zc0301_write_reg(cam, 0x0139, 0x09);
104         err += zc0301_write_reg(cam, 0x013A, 0x07);
105         err += zc0301_write_reg(cam, 0x013B, 0x06);
106         err += zc0301_write_reg(cam, 0x013C, 0x05);
107         err += zc0301_write_reg(cam, 0x013D, 0x04);
108         err += zc0301_write_reg(cam, 0x013E, 0x03);
109         err += zc0301_write_reg(cam, 0x013F, 0x02);
110         err += zc0301_write_reg(cam, 0x010A, 0x4C);
111         err += zc0301_write_reg(cam, 0x010B, 0xF5);
112         err += zc0301_write_reg(cam, 0x010C, 0xFF);
113         err += zc0301_write_reg(cam, 0x010D, 0xF9);
114         err += zc0301_write_reg(cam, 0x010E, 0x51);
115         err += zc0301_write_reg(cam, 0x010F, 0xF5);
116         err += zc0301_write_reg(cam, 0x0110, 0xFB);
117         err += zc0301_write_reg(cam, 0x0111, 0xED);
118         err += zc0301_write_reg(cam, 0x0112, 0x5F);
119         err += zc0301_write_reg(cam, 0x0180, 0x00);
120         err += zc0301_write_reg(cam, 0x0019, 0x00);
121         err += zc0301_write_reg(cam, 0x0087, 0x20);
122         err += zc0301_write_reg(cam, 0x0088, 0x21);
123
124         err += zc0301_i2c_write(cam, 0x20, 0x02);
125         err += zc0301_i2c_write(cam, 0x21, 0x1B);
126         err += zc0301_i2c_write(cam, 0x03, 0x44);
127         err += zc0301_i2c_write(cam, 0x0E, 0x01);
128         err += zc0301_i2c_write(cam, 0x0F, 0x00);
129
130         err += zc0301_write_reg(cam, 0x01A9, 0x14);
131         err += zc0301_write_reg(cam, 0x01AA, 0x24);
132         err += zc0301_write_reg(cam, 0x0190, 0x00);
133         err += zc0301_write_reg(cam, 0x0191, 0x02);
134         err += zc0301_write_reg(cam, 0x0192, 0x1B);
135         err += zc0301_write_reg(cam, 0x0195, 0x00);
136         err += zc0301_write_reg(cam, 0x0196, 0x00);
137         err += zc0301_write_reg(cam, 0x0197, 0x4D);
138         err += zc0301_write_reg(cam, 0x018C, 0x10);
139         err += zc0301_write_reg(cam, 0x018F, 0x20);
140         err += zc0301_write_reg(cam, 0x001D, 0x44);
141         err += zc0301_write_reg(cam, 0x001E, 0x6F);
142         err += zc0301_write_reg(cam, 0x001F, 0xAD);
143         err += zc0301_write_reg(cam, 0x0020, 0xEB);
144         err += zc0301_write_reg(cam, 0x0087, 0x0F);
145         err += zc0301_write_reg(cam, 0x0088, 0x0E);
146         err += zc0301_write_reg(cam, 0x0180, 0x40);
147         err += zc0301_write_reg(cam, 0x0192, 0x1B);
148         err += zc0301_write_reg(cam, 0x0191, 0x02);
149         err += zc0301_write_reg(cam, 0x0190, 0x00);
150         err += zc0301_write_reg(cam, 0x0116, 0x1D);
151         err += zc0301_write_reg(cam, 0x0117, 0x40);
152         err += zc0301_write_reg(cam, 0x0118, 0x99);
153         err += zc0301_write_reg(cam, 0x0180, 0x42);
154         err += zc0301_write_reg(cam, 0x0116, 0x1D);
155         err += zc0301_write_reg(cam, 0x0117, 0x40);
156         err += zc0301_write_reg(cam, 0x0118, 0x99);
157         err += zc0301_write_reg(cam, 0x0007, 0x00);
158
159         err += zc0301_i2c_write(cam, 0x11, 0x01);
160
161         msleep(100);
162
163         return err;
164 }
165
166
167 static int pas202bcb_get_ctrl(struct zc0301_device* cam,
168                               struct v4l2_control* ctrl)
169 {
170         switch (ctrl->id) {
171         case V4L2_CID_EXPOSURE:
172                 {
173                         int r1 = zc0301_i2c_read(cam, 0x04, 1),
174                             r2 = zc0301_i2c_read(cam, 0x05, 1);
175                         if (r1 < 0 || r2 < 0)
176                                 return -EIO;
177                         ctrl->value = (r1 << 6) | (r2 & 0x3f);
178                 }
179                 return 0;
180         case V4L2_CID_RED_BALANCE:
181                 if ((ctrl->value = zc0301_i2c_read(cam, 0x09, 1)) < 0)
182                         return -EIO;
183                 ctrl->value &= 0x0f;
184                 return 0;
185         case V4L2_CID_BLUE_BALANCE:
186                 if ((ctrl->value = zc0301_i2c_read(cam, 0x07, 1)) < 0)
187                         return -EIO;
188                 ctrl->value &= 0x0f;
189                 return 0;
190         case V4L2_CID_GAIN:
191                 if ((ctrl->value = zc0301_i2c_read(cam, 0x10, 1)) < 0)
192                         return -EIO;
193                 ctrl->value &= 0x1f;
194                 return 0;
195         case ZC0301_V4L2_CID_GREEN_BALANCE:
196                 if ((ctrl->value = zc0301_i2c_read(cam, 0x08, 1)) < 0)
197                         return -EIO;
198                 ctrl->value &= 0x0f;
199                 return 0;
200         case ZC0301_V4L2_CID_DAC_MAGNITUDE:
201                 if ((ctrl->value = zc0301_i2c_read(cam, 0x0c, 1)) < 0)
202                         return -EIO;
203                 return 0;
204         default:
205                 return -EINVAL;
206         }
207 }
208
209
210 static int pas202bcb_set_ctrl(struct zc0301_device* cam,
211                               const struct v4l2_control* ctrl)
212 {
213         int err = 0;
214
215         switch (ctrl->id) {
216         case V4L2_CID_EXPOSURE:
217                 err += zc0301_i2c_write(cam, 0x04, ctrl->value >> 6);
218                 err += zc0301_i2c_write(cam, 0x05, ctrl->value & 0x3f);
219                 break;
220         case V4L2_CID_RED_BALANCE:
221                 err += zc0301_i2c_write(cam, 0x09, ctrl->value);
222                 break;
223         case V4L2_CID_BLUE_BALANCE:
224                 err += zc0301_i2c_write(cam, 0x07, ctrl->value);
225                 break;
226         case V4L2_CID_GAIN:
227                 err += zc0301_i2c_write(cam, 0x10, ctrl->value);
228                 break;
229         case ZC0301_V4L2_CID_GREEN_BALANCE:
230                 err += zc0301_i2c_write(cam, 0x08, ctrl->value);
231                 break;
232         case ZC0301_V4L2_CID_DAC_MAGNITUDE:
233                 err += zc0301_i2c_write(cam, 0x0c, ctrl->value);
234                 break;
235         default:
236                 return -EINVAL;
237         }
238         err += zc0301_i2c_write(cam, 0x11, 0x01);
239
240         return err ? -EIO : 0;
241 }
242
243
244 static struct zc0301_sensor pas202bcb = {
245         .name = "PAS202BCB",
246         .init = &pas202bcb_init,
247         .qctrl = {
248                 {
249                         .id = V4L2_CID_EXPOSURE,
250                         .type = V4L2_CTRL_TYPE_INTEGER,
251                         .name = "exposure",
252                         .minimum = 0x01e5,
253                         .maximum = 0x3fff,
254                         .step = 0x0001,
255                         .default_value = 0x01e5,
256                         .flags = V4L2_CTRL_FLAG_DISABLED,
257                 },
258                 {
259                         .id = V4L2_CID_GAIN,
260                         .type = V4L2_CTRL_TYPE_INTEGER,
261                         .name = "global gain",
262                         .minimum = 0x00,
263                         .maximum = 0x1f,
264                         .step = 0x01,
265                         .default_value = 0x0c,
266                         .flags = V4L2_CTRL_FLAG_DISABLED,
267                 },
268                 {
269                         .id = ZC0301_V4L2_CID_DAC_MAGNITUDE,
270                         .type = V4L2_CTRL_TYPE_INTEGER,
271                         .name = "DAC magnitude",
272                         .minimum = 0x00,
273                         .maximum = 0xff,
274                         .step = 0x01,
275                         .default_value = 0x00,
276                         .flags = V4L2_CTRL_FLAG_DISABLED,
277                 },
278                 {
279                         .id = V4L2_CID_RED_BALANCE,
280                         .type = V4L2_CTRL_TYPE_INTEGER,
281                         .name = "red balance",
282                         .minimum = 0x00,
283                         .maximum = 0x0f,
284                         .step = 0x01,
285                         .default_value = 0x01,
286                         .flags = V4L2_CTRL_FLAG_DISABLED,
287                 },
288                 {
289                         .id = V4L2_CID_BLUE_BALANCE,
290                         .type = V4L2_CTRL_TYPE_INTEGER,
291                         .name = "blue balance",
292                         .minimum = 0x00,
293                         .maximum = 0x0f,
294                         .step = 0x01,
295                         .default_value = 0x05,
296                         .flags = V4L2_CTRL_FLAG_DISABLED,
297                 },
298                 {
299                         .id = ZC0301_V4L2_CID_GREEN_BALANCE,
300                         .type = V4L2_CTRL_TYPE_INTEGER,
301                         .name = "green balance",
302                         .minimum = 0x00,
303                         .maximum = 0x0f,
304                         .step = 0x01,
305                         .default_value = 0x00,
306                         .flags = V4L2_CTRL_FLAG_DISABLED,
307                 },
308         },
309         .get_ctrl = &pas202bcb_get_ctrl,
310         .set_ctrl = &pas202bcb_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         .pix_format = {
326                 .width = 640,
327                 .height = 480,
328                 .pixelformat = V4L2_PIX_FMT_JPEG,
329                 .priv = 8,
330                 .colorspace = V4L2_COLORSPACE_JPEG,
331         },
332 };
333
334
335 int zc0301_probe_pas202bcb(struct zc0301_device* cam)
336 {
337         int r0 = 0, r1 = 0, err = 0;
338         unsigned int pid = 0;
339
340         err += zc0301_write_reg(cam, 0x0000, 0x01);
341         err += zc0301_write_reg(cam, 0x0010, 0x0e);
342         err += zc0301_write_reg(cam, 0x0001, 0x01);
343         err += zc0301_write_reg(cam, 0x0012, 0x03);
344         err += zc0301_write_reg(cam, 0x0012, 0x01);
345         err += zc0301_write_reg(cam, 0x008d, 0x08);
346
347         msleep(10);
348
349         r0 = zc0301_i2c_read(cam, 0x00, 1);
350         r1 = zc0301_i2c_read(cam, 0x01, 1);
351
352         if (r0 < 0 || r1 < 0 || err)
353                 return -EIO;
354
355         pid = (r0 << 4) | ((r1 & 0xf0) >> 4);
356         if (pid != 0x017)
357                 return -ENODEV;
358
359         zc0301_attach_sensor(cam, &pas202bcb);
360
361         return 0;
362 }