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