V4L/DVB (5311): Tda1004x driver updates
[linux-2.6] / drivers / media / video / sn9c102 / sn9c102_pas202bcb.c
1 /***************************************************************************
2  * Plug-in for PAS202BCB image sensor connected to the SN9C1xx PC Camera   *
3  * Controllers                                                             *
4  *                                                                         *
5  * Copyright (C) 2004 by Carlos Eduardo Medaglia Dyonisio                  *
6  *                       <medaglia@undl.org.br>                            *
7  *                       http://cadu.homelinux.com:8080/                   *
8  *                                                                         *
9  * Support for SN9C103, DAC Magnitude, exposure and green gain controls    *
10  * added by Luca Risolia <luca.risolia@studio.unibo.it>                    *
11  *                                                                         *
12  * This program is free software; you can redistribute it and/or modify    *
13  * it under the terms of the GNU General Public License as published by    *
14  * the Free Software Foundation; either version 2 of the License, or       *
15  * (at your option) any later version.                                     *
16  *                                                                         *
17  * This program is distributed in the hope that it will be useful,         *
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
20  * GNU General Public License for more details.                            *
21  *                                                                         *
22  * You should have received a copy of the GNU General Public License       *
23  * along with this program; if not, write to the Free Software             *
24  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
25  ***************************************************************************/
26
27 #include <linux/delay.h>
28 #include "sn9c102_sensor.h"
29
30
31 static struct sn9c102_sensor pas202bcb;
32
33
34 static int pas202bcb_init(struct sn9c102_device* cam)
35 {
36         int err = 0;
37
38         switch (sn9c102_get_bridge(cam)) {
39         case BRIDGE_SN9C101:
40         case BRIDGE_SN9C102:
41         err += sn9c102_write_reg(cam, 0x00, 0x10);
42         err += sn9c102_write_reg(cam, 0x00, 0x11);
43         err += sn9c102_write_reg(cam, 0x00, 0x14);
44         err += sn9c102_write_reg(cam, 0x20, 0x17);
45         err += sn9c102_write_reg(cam, 0x30, 0x19);
46         err += sn9c102_write_reg(cam, 0x09, 0x18);
47                 break;
48         case BRIDGE_SN9C103:
49                 err += sn9c102_write_reg(cam, 0x00, 0x02);
50                 err += sn9c102_write_reg(cam, 0x00, 0x03);
51                 err += sn9c102_write_reg(cam, 0x1a, 0x04);
52                 err += sn9c102_write_reg(cam, 0x20, 0x05);
53                 err += sn9c102_write_reg(cam, 0x20, 0x06);
54                 err += sn9c102_write_reg(cam, 0x20, 0x07);
55                 err += sn9c102_write_reg(cam, 0x00, 0x10);
56                 err += sn9c102_write_reg(cam, 0x00, 0x11);
57                 err += sn9c102_write_reg(cam, 0x00, 0x14);
58                 err += sn9c102_write_reg(cam, 0x20, 0x17);
59                 err += sn9c102_write_reg(cam, 0x30, 0x19);
60                 err += sn9c102_write_reg(cam, 0x09, 0x18);
61                 err += sn9c102_write_reg(cam, 0x02, 0x1c);
62                 err += sn9c102_write_reg(cam, 0x03, 0x1d);
63                 err += sn9c102_write_reg(cam, 0x0f, 0x1e);
64                 err += sn9c102_write_reg(cam, 0x0c, 0x1f);
65                 err += sn9c102_write_reg(cam, 0x00, 0x20);
66                 err += sn9c102_write_reg(cam, 0x10, 0x21);
67                 err += sn9c102_write_reg(cam, 0x20, 0x22);
68                 err += sn9c102_write_reg(cam, 0x30, 0x23);
69                 err += sn9c102_write_reg(cam, 0x40, 0x24);
70                 err += sn9c102_write_reg(cam, 0x50, 0x25);
71                 err += sn9c102_write_reg(cam, 0x60, 0x26);
72                 err += sn9c102_write_reg(cam, 0x70, 0x27);
73                 err += sn9c102_write_reg(cam, 0x80, 0x28);
74                 err += sn9c102_write_reg(cam, 0x90, 0x29);
75                 err += sn9c102_write_reg(cam, 0xa0, 0x2a);
76                 err += sn9c102_write_reg(cam, 0xb0, 0x2b);
77                 err += sn9c102_write_reg(cam, 0xc0, 0x2c);
78                 err += sn9c102_write_reg(cam, 0xd0, 0x2d);
79                 err += sn9c102_write_reg(cam, 0xe0, 0x2e);
80                 err += sn9c102_write_reg(cam, 0xf0, 0x2f);
81                 err += sn9c102_write_reg(cam, 0xff, 0x30);
82                 break;
83         default:
84                 break;
85         }
86
87         err += sn9c102_i2c_write(cam, 0x02, 0x14);
88         err += sn9c102_i2c_write(cam, 0x03, 0x40);
89         err += sn9c102_i2c_write(cam, 0x0d, 0x2c);
90         err += sn9c102_i2c_write(cam, 0x0e, 0x01);
91         err += sn9c102_i2c_write(cam, 0x0f, 0xa9);
92         err += sn9c102_i2c_write(cam, 0x10, 0x08);
93         err += sn9c102_i2c_write(cam, 0x13, 0x63);
94         err += sn9c102_i2c_write(cam, 0x15, 0x70);
95         err += sn9c102_i2c_write(cam, 0x11, 0x01);
96
97         msleep(400);
98
99         return err;
100 }
101
102
103 static int pas202bcb_get_ctrl(struct sn9c102_device* cam,
104                               struct v4l2_control* ctrl)
105 {
106         switch (ctrl->id) {
107         case V4L2_CID_EXPOSURE:
108                 {
109                         int r1 = sn9c102_i2c_read(cam, 0x04),
110                             r2 = sn9c102_i2c_read(cam, 0x05);
111                         if (r1 < 0 || r2 < 0)
112                                 return -EIO;
113                         ctrl->value = (r1 << 6) | (r2 & 0x3f);
114                 }
115                 return 0;
116         case V4L2_CID_RED_BALANCE:
117                 if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0)
118                         return -EIO;
119                 ctrl->value &= 0x0f;
120                 return 0;
121         case V4L2_CID_BLUE_BALANCE:
122                 if ((ctrl->value = sn9c102_i2c_read(cam, 0x07)) < 0)
123                         return -EIO;
124                 ctrl->value &= 0x0f;
125                 return 0;
126         case V4L2_CID_GAIN:
127                 if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0)
128                         return -EIO;
129                 ctrl->value &= 0x1f;
130                 return 0;
131         case SN9C102_V4L2_CID_GREEN_BALANCE:
132                 if ((ctrl->value = sn9c102_i2c_read(cam, 0x08)) < 0)
133                         return -EIO;
134                 ctrl->value &= 0x0f;
135                 return 0;
136         case SN9C102_V4L2_CID_DAC_MAGNITUDE:
137                 if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0)
138                         return -EIO;
139                 return 0;
140         default:
141                 return -EINVAL;
142         }
143 }
144
145
146 static int pas202bcb_set_pix_format(struct sn9c102_device* cam,
147                                     const struct v4l2_pix_format* pix)
148 {
149         int err = 0;
150
151         if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
152                 err += sn9c102_write_reg(cam, 0x28, 0x17);
153         else
154                 err += sn9c102_write_reg(cam, 0x20, 0x17);
155
156         return err;
157 }
158
159
160 static int pas202bcb_set_ctrl(struct sn9c102_device* cam,
161                               const struct v4l2_control* ctrl)
162 {
163         int err = 0;
164
165         switch (ctrl->id) {
166         case V4L2_CID_EXPOSURE:
167                 err += sn9c102_i2c_write(cam, 0x04, ctrl->value >> 6);
168                 err += sn9c102_i2c_write(cam, 0x05, ctrl->value & 0x3f);
169                 break;
170         case V4L2_CID_RED_BALANCE:
171                 err += sn9c102_i2c_write(cam, 0x09, ctrl->value);
172                 break;
173         case V4L2_CID_BLUE_BALANCE:
174                 err += sn9c102_i2c_write(cam, 0x07, ctrl->value);
175                 break;
176         case V4L2_CID_GAIN:
177                 err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
178                 break;
179         case SN9C102_V4L2_CID_GREEN_BALANCE:
180                 err += sn9c102_i2c_write(cam, 0x08, ctrl->value);
181                 break;
182         case SN9C102_V4L2_CID_DAC_MAGNITUDE:
183                 err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
184                 break;
185         default:
186                 return -EINVAL;
187         }
188         err += sn9c102_i2c_write(cam, 0x11, 0x01);
189
190         return err ? -EIO : 0;
191 }
192
193
194 static int pas202bcb_set_crop(struct sn9c102_device* cam,
195                               const struct v4l2_rect* rect)
196 {
197         struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
198         int err = 0;
199         u8 h_start = 0,
200            v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
201
202         switch (sn9c102_get_bridge(cam)) {
203         case BRIDGE_SN9C101:
204         case BRIDGE_SN9C102:
205                 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4;
206                 break;
207         case BRIDGE_SN9C103:
208                 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 3;
209                 break;
210         default:
211                 break;
212         }
213
214         err += sn9c102_write_reg(cam, h_start, 0x12);
215         err += sn9c102_write_reg(cam, v_start, 0x13);
216
217         return err;
218 }
219
220
221 static struct sn9c102_sensor pas202bcb = {
222         .name = "PAS202BCB",
223         .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
224         .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
225         .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
226         .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
227         .interface = SN9C102_I2C_2WIRES,
228         .i2c_slave_id = 0x40,
229         .init = &pas202bcb_init,
230         .qctrl = {
231                 {
232                         .id = V4L2_CID_EXPOSURE,
233                         .type = V4L2_CTRL_TYPE_INTEGER,
234                         .name = "exposure",
235                         .minimum = 0x01e5,
236                         .maximum = 0x3fff,
237                         .step = 0x0001,
238                         .default_value = 0x01e5,
239                         .flags = 0,
240                 },
241                 {
242                         .id = V4L2_CID_GAIN,
243                         .type = V4L2_CTRL_TYPE_INTEGER,
244                         .name = "global gain",
245                         .minimum = 0x00,
246                         .maximum = 0x1f,
247                         .step = 0x01,
248                         .default_value = 0x0b,
249                         .flags = 0,
250                 },
251                 {
252                         .id = V4L2_CID_RED_BALANCE,
253                         .type = V4L2_CTRL_TYPE_INTEGER,
254                         .name = "red balance",
255                         .minimum = 0x00,
256                         .maximum = 0x0f,
257                         .step = 0x01,
258                         .default_value = 0x00,
259                         .flags = 0,
260                 },
261                 {
262                         .id = V4L2_CID_BLUE_BALANCE,
263                         .type = V4L2_CTRL_TYPE_INTEGER,
264                         .name = "blue balance",
265                         .minimum = 0x00,
266                         .maximum = 0x0f,
267                         .step = 0x01,
268                         .default_value = 0x05,
269                         .flags = 0,
270                 },
271                 {
272                         .id = SN9C102_V4L2_CID_GREEN_BALANCE,
273                         .type = V4L2_CTRL_TYPE_INTEGER,
274                         .name = "green balance",
275                         .minimum = 0x00,
276                         .maximum = 0x0f,
277                         .step = 0x01,
278                         .default_value = 0x00,
279                         .flags = 0,
280                 },
281                 {
282                         .id = SN9C102_V4L2_CID_DAC_MAGNITUDE,
283                         .type = V4L2_CTRL_TYPE_INTEGER,
284                         .name = "DAC magnitude",
285                         .minimum = 0x00,
286                         .maximum = 0xff,
287                         .step = 0x01,
288                         .default_value = 0x04,
289                         .flags = 0,
290                 },
291         },
292         .get_ctrl = &pas202bcb_get_ctrl,
293         .set_ctrl = &pas202bcb_set_ctrl,
294         .cropcap = {
295                 .bounds = {
296                         .left = 0,
297                         .top = 0,
298                         .width = 640,
299                         .height = 480,
300                 },
301                 .defrect = {
302                         .left = 0,
303                         .top = 0,
304                         .width = 640,
305                         .height = 480,
306                 },
307         },
308         .set_crop = &pas202bcb_set_crop,
309         .pix_format = {
310                 .width = 640,
311                 .height = 480,
312                 .pixelformat = V4L2_PIX_FMT_SBGGR8,
313                 .priv = 8,
314         },
315         .set_pix_format = &pas202bcb_set_pix_format
316 };
317
318
319 int sn9c102_probe_pas202bcb(struct sn9c102_device* cam)
320 {
321         int r0 = 0, r1 = 0, err = 0;
322         unsigned int pid = 0;
323
324         /*
325          *  Minimal initialization to enable the I2C communication
326          *  NOTE: do NOT change the values!
327          */
328         switch (sn9c102_get_bridge(cam)) {
329         case BRIDGE_SN9C101:
330         case BRIDGE_SN9C102:
331                 err += sn9c102_write_reg(cam, 0x01, 0x01); /* power down */
332                 err += sn9c102_write_reg(cam, 0x40, 0x01); /* power on */
333                 err += sn9c102_write_reg(cam, 0x28, 0x17); /* clock 24 MHz */
334                 break;
335         case BRIDGE_SN9C103: /* do _not_ change anything! */
336                 err += sn9c102_write_reg(cam, 0x09, 0x01);
337                 err += sn9c102_write_reg(cam, 0x44, 0x01);
338                 err += sn9c102_write_reg(cam, 0x44, 0x02);
339                 err += sn9c102_write_reg(cam, 0x29, 0x17);
340                 break;
341         default:
342                 break;
343         }
344
345         r0 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x00);
346         r1 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x01);
347
348         if (err || r0 < 0 || r1 < 0)
349                 return -EIO;
350
351         pid = (r0 << 4) | ((r1 & 0xf0) >> 4);
352         if (pid != 0x017)
353                 return -ENODEV;
354
355         sn9c102_attach_sensor(cam, &pas202bcb);
356
357         return 0;
358 }