This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / drivers / usb / media / sn9c102_pas202bcb.c
1 /***************************************************************************
2  * Driver for PAS202BCB image sensor connected to the SN9C10[12] 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  * This program is free software; you can redistribute it and/or modify    *
10  * it under the terms of the GNU General Public License as published by    *
11  * the Free Software Foundation; either version 2 of the License, or       *
12  * (at your option) any later version.                                     *
13  *                                                                         *
14  * This program is distributed in the hope that it will be useful,         *
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
17  * GNU General Public License for more details.                            *
18  *                                                                         *
19  * You should have received a copy of the GNU General Public License       *
20  * along with this program; if not, write to the Free Software             *
21  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
22  ***************************************************************************/
23
24 #include <linux/delay.h>
25 #include "sn9c102_sensor.h"
26
27
28 static struct sn9c102_sensor pas202bcb;
29
30
31 static int pas202bcb_init(struct sn9c102_device* cam)
32 {
33         int err = 0;
34
35         err += sn9c102_write_reg(cam, 0x00, 0x10);
36         err += sn9c102_write_reg(cam, 0x00, 0x11);
37         err += sn9c102_write_reg(cam, 0x00, 0x14);
38         err += sn9c102_write_reg(cam, 0x20, 0x17);
39         err += sn9c102_write_reg(cam, 0x20, 0x19);
40         err += sn9c102_write_reg(cam, 0x09, 0x18);
41
42         err += sn9c102_i2c_write(cam, 0x02, 0x0c);
43         err += sn9c102_i2c_write(cam, 0x03, 0x40);
44         err += sn9c102_i2c_write(cam, 0x04, 0x07);
45         err += sn9c102_i2c_write(cam, 0x05, 0x25);
46         err += sn9c102_i2c_write(cam, 0x0d, 0x2c);
47         err += sn9c102_i2c_write(cam, 0x0e, 0x01);
48         err += sn9c102_i2c_write(cam, 0x0f, 0xa9);
49         err += sn9c102_i2c_write(cam, 0x08, 0x01);
50         err += sn9c102_i2c_write(cam, 0x0b, 0x01);
51         err += sn9c102_i2c_write(cam, 0x13, 0x63);
52         err += sn9c102_i2c_write(cam, 0x15, 0x70);
53         err += sn9c102_i2c_write(cam, 0x11, 0x01);
54
55         msleep(400);
56
57         return err;
58 }
59
60
61 static int pas202bcb_get_ctrl(struct sn9c102_device* cam, 
62                               struct v4l2_control* ctrl)
63 {
64         switch (ctrl->id) {
65         case V4L2_CID_RED_BALANCE:
66                 if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0)
67                         return -EIO;
68                 ctrl->value &= 0x0f;
69                 return 0;
70         case V4L2_CID_BLUE_BALANCE:
71                 if ((ctrl->value = sn9c102_i2c_read(cam, 0x07)) < 0)
72                         return -EIO;
73                 ctrl->value &= 0x0f;
74                 return 0;
75         case V4L2_CID_GAIN:
76                 if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0)
77                         return -EIO;
78                 ctrl->value &= 0x1f;
79                 return 0;
80         case V4L2_CID_BRIGHTNESS:
81                 if ((ctrl->value = sn9c102_i2c_read(cam, 0x06)) < 0)
82                         return -EIO;
83                 ctrl->value &= 0x0f;
84                 return 0;
85         default:
86                 return -EINVAL;
87         }
88 }
89
90
91 static int pas202bcb_set_ctrl(struct sn9c102_device* cam, 
92                               const struct v4l2_control* ctrl)
93 {
94         int err = 0;
95
96         switch (ctrl->id) {
97         case V4L2_CID_RED_BALANCE:
98                 err += sn9c102_i2c_write(cam, 0x09, ctrl->value & 0x0f);
99                 break;
100         case V4L2_CID_BLUE_BALANCE:
101                 err += sn9c102_i2c_write(cam, 0x07, ctrl->value & 0x0f);
102                 break;
103         case V4L2_CID_GAIN:
104                 err += sn9c102_i2c_write(cam, 0x10, ctrl->value & 0x1f);
105                 break;
106         case V4L2_CID_BRIGHTNESS:
107                 err += sn9c102_i2c_write(cam, 0x06, 0x0f-(ctrl->value & 0x0f));
108                 break;
109         default:
110                 return -EINVAL;
111         }
112         err += sn9c102_i2c_write(cam, 0x11, 0x01);
113
114         return err;
115 }
116
117
118 static int pas202bcb_set_crop(struct sn9c102_device* cam, 
119                               const struct v4l2_rect* rect)
120 {
121         struct sn9c102_sensor* s = &pas202bcb;
122         int err = 0;
123         u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4,
124            v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
125
126         err += sn9c102_write_reg(cam, h_start, 0x12);
127         err += sn9c102_write_reg(cam, v_start, 0x13);
128
129         return err;
130 }
131
132
133 static struct sn9c102_sensor pas202bcb = {
134         .name = "PAS202BCB",
135         .maintainer = "Carlos Eduardo Medaglia Dyonisio "
136                       "<medaglia@undl.org.br>",
137         .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
138         .interface = SN9C102_I2C_2WIRES,
139         .slave_read_id = 0x40,
140         .slave_write_id = 0x40,
141         .init = &pas202bcb_init,
142         .qctrl = {
143                 {
144                         .id = V4L2_CID_RED_BALANCE,
145                         .type = V4L2_CTRL_TYPE_INTEGER,
146                         .name = "red balance",
147                         .minimum = 0x00,
148                         .maximum = 0x0f,
149                         .step = 0x01,
150                         .default_value = 0x01,
151                         .flags = 0,
152                 },
153                 {
154                         .id = V4L2_CID_BLUE_BALANCE,
155                         .type = V4L2_CTRL_TYPE_INTEGER,
156                         .name = "blue balance",
157                         .minimum = 0x00,
158                         .maximum = 0x0f,
159                         .step = 0x01,
160                         .default_value = 0x05,
161                         .flags = 0,
162                 },
163                 {
164                         .id = V4L2_CID_GAIN,
165                         .type = V4L2_CTRL_TYPE_INTEGER,
166                         .name = "global gain",
167                         .minimum = 0x00,
168                         .maximum = 0x1f,
169                         .step = 0x01,
170                         .default_value = 0x0c,
171                         .flags = 0,
172                 },
173                 {
174                         .id = V4L2_CID_BRIGHTNESS,
175                         .type = V4L2_CTRL_TYPE_INTEGER,
176                         .name = "brightness",
177                         .minimum = 0x00,
178                         .maximum = 0x0f,
179                         .step = 0x01,
180                         .default_value = 0x0f,
181                         .flags = 0,
182                 },
183         },
184         .get_ctrl = &pas202bcb_get_ctrl,
185         .set_ctrl = &pas202bcb_set_ctrl,
186         .cropcap = {
187                 .bounds = {
188                         .left = 0,
189                         .top = 0,
190                         .width = 640,
191                         .height = 480,
192                 },
193                 .defrect = {
194                         .left = 0,
195                         .top = 0,
196                         .width = 640,
197                         .height = 480,
198                 },
199         },
200         .set_crop = &pas202bcb_set_crop,
201         .pix_format = {
202                 .width = 640,
203                 .height = 480,
204                 .pixelformat = V4L2_PIX_FMT_SBGGR8,
205                 .priv = 8,
206         }
207 };
208
209
210 int sn9c102_probe_pas202bcb(struct sn9c102_device* cam)
211 {       
212         int r0 = 0, r1 = 0, err = 0;
213         unsigned int pid = 0;
214
215         /*
216          *  Minimal initialization to enable the I2C communication
217          *  NOTE: do NOT change the values!
218          */
219         err += sn9c102_write_reg(cam, 0x01, 0x01); /* sensor power down */
220         err += sn9c102_write_reg(cam, 0x00, 0x01); /* sensor power on */
221         err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 24 MHz */
222         if (err)
223                 return -EIO;
224
225         r0 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x00);
226         r1 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x01);
227         
228         if (r0 < 0 || r1 < 0)
229                 return -EIO;
230
231         pid = (r0 << 4) | ((r1 & 0xf0) >> 4);
232         if (pid != 0x017)
233                 return -ENODEV;
234
235         sn9c102_attach_sensor(cam, &pas202bcb);
236
237         return 0;
238 }