Merge branch 'for-linus' of master.kernel.org:/pub/scm/linux/kernel/git/roland/infiniband
[linux-2.6] / drivers / media / video / sn9c102 / sn9c102_pas202bca.c
1 /***************************************************************************
2  * Plug-in for PAS202BCA image sensor connected to the SN9C10x PC Camera   *
3  * Controllers                                                             *
4  *                                                                         *
5  * Copyright (C) 2006 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 <linux/delay.h>
23 #include "sn9c102_sensor.h"
24
25
26 static struct sn9c102_sensor pas202bca;
27
28
29 static int pas202bca_init(struct sn9c102_device* cam)
30 {
31         int err = 0;
32
33         err += sn9c102_write_reg(cam, 0x00, 0x10);
34         err += sn9c102_write_reg(cam, 0x00, 0x11);
35         err += sn9c102_write_reg(cam, 0x00, 0x14);
36         err += sn9c102_write_reg(cam, 0x20, 0x17);
37         err += sn9c102_write_reg(cam, 0x30, 0x19);
38         err += sn9c102_write_reg(cam, 0x09, 0x18);
39
40         err += sn9c102_i2c_write(cam, 0x02, 0x14);
41         err += sn9c102_i2c_write(cam, 0x03, 0x40);
42         err += sn9c102_i2c_write(cam, 0x0d, 0x2c);
43         err += sn9c102_i2c_write(cam, 0x0e, 0x01);
44         err += sn9c102_i2c_write(cam, 0x0f, 0xa9);
45         err += sn9c102_i2c_write(cam, 0x10, 0x08);
46         err += sn9c102_i2c_write(cam, 0x13, 0x63);
47         err += sn9c102_i2c_write(cam, 0x15, 0x70);
48         err += sn9c102_i2c_write(cam, 0x11, 0x01);
49
50         msleep(400);
51
52         return err;
53 }
54
55
56 static int pas202bca_set_pix_format(struct sn9c102_device* cam,
57                                     const struct v4l2_pix_format* pix)
58 {
59         int err = 0;
60
61         if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
62                 err += sn9c102_write_reg(cam, 0x24, 0x17);
63         else
64                 err += sn9c102_write_reg(cam, 0x20, 0x17);
65
66         return err;
67 }
68
69
70 static int pas202bca_set_ctrl(struct sn9c102_device* cam,
71                               const struct v4l2_control* ctrl)
72 {
73         int err = 0;
74
75         switch (ctrl->id) {
76         case V4L2_CID_EXPOSURE:
77                 err += sn9c102_i2c_write(cam, 0x04, ctrl->value >> 6);
78                 err += sn9c102_i2c_write(cam, 0x05, ctrl->value & 0x3f);
79                 break;
80         case V4L2_CID_RED_BALANCE:
81                 err += sn9c102_i2c_write(cam, 0x09, ctrl->value);
82                 break;
83         case V4L2_CID_BLUE_BALANCE:
84                 err += sn9c102_i2c_write(cam, 0x07, ctrl->value);
85                 break;
86         case V4L2_CID_GAIN:
87                 err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
88                 break;
89         case SN9C102_V4L2_CID_GREEN_BALANCE:
90                 err += sn9c102_i2c_write(cam, 0x08, ctrl->value);
91                 break;
92         case SN9C102_V4L2_CID_DAC_MAGNITUDE:
93                 err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
94                 break;
95         default:
96                 return -EINVAL;
97         }
98         err += sn9c102_i2c_write(cam, 0x11, 0x01);
99
100         return err ? -EIO : 0;
101 }
102
103
104 static int pas202bca_set_crop(struct sn9c102_device* cam,
105                               const struct v4l2_rect* rect)
106 {
107         struct sn9c102_sensor* s = &pas202bca;
108         int err = 0;
109         u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 3,
110            v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
111
112         err += sn9c102_write_reg(cam, h_start, 0x12);
113         err += sn9c102_write_reg(cam, v_start, 0x13);
114
115         return err;
116 }
117
118
119 static struct sn9c102_sensor pas202bca = {
120         .name = "PAS202BCA",
121         .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
122         .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
123         .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
124         .interface = SN9C102_I2C_2WIRES,
125         .i2c_slave_id = 0x40,
126         .init = &pas202bca_init,
127         .qctrl = {
128                 {
129                         .id = V4L2_CID_EXPOSURE,
130                         .type = V4L2_CTRL_TYPE_INTEGER,
131                         .name = "exposure",
132                         .minimum = 0x01e5,
133                         .maximum = 0x3fff,
134                         .step = 0x0001,
135                         .default_value = 0x01e5,
136                         .flags = 0,
137                 },
138                 {
139                         .id = V4L2_CID_GAIN,
140                         .type = V4L2_CTRL_TYPE_INTEGER,
141                         .name = "global gain",
142                         .minimum = 0x00,
143                         .maximum = 0x1f,
144                         .step = 0x01,
145                         .default_value = 0x0c,
146                         .flags = 0,
147                 },
148                 {
149                         .id = V4L2_CID_RED_BALANCE,
150                         .type = V4L2_CTRL_TYPE_INTEGER,
151                         .name = "red balance",
152                         .minimum = 0x00,
153                         .maximum = 0x0f,
154                         .step = 0x01,
155                         .default_value = 0x01,
156                         .flags = 0,
157                 },
158                 {
159                         .id = V4L2_CID_BLUE_BALANCE,
160                         .type = V4L2_CTRL_TYPE_INTEGER,
161                         .name = "blue balance",
162                         .minimum = 0x00,
163                         .maximum = 0x0f,
164                         .step = 0x01,
165                         .default_value = 0x05,
166                         .flags = 0,
167                 },
168                 {
169                         .id = SN9C102_V4L2_CID_GREEN_BALANCE,
170                         .type = V4L2_CTRL_TYPE_INTEGER,
171                         .name = "green balance",
172                         .minimum = 0x00,
173                         .maximum = 0x0f,
174                         .step = 0x01,
175                         .default_value = 0x00,
176                         .flags = 0,
177                 },
178                 {
179                         .id = SN9C102_V4L2_CID_DAC_MAGNITUDE,
180                         .type = V4L2_CTRL_TYPE_INTEGER,
181                         .name = "DAC magnitude",
182                         .minimum = 0x00,
183                         .maximum = 0xff,
184                         .step = 0x01,
185                         .default_value = 0x04,
186                         .flags = 0,
187                 },
188         },
189         .set_ctrl = &pas202bca_set_ctrl,
190         .cropcap = {
191                 .bounds = {
192                         .left = 0,
193                         .top = 0,
194                         .width = 640,
195                         .height = 480,
196                 },
197                 .defrect = {
198                         .left = 0,
199                         .top = 0,
200                         .width = 640,
201                         .height = 480,
202                 },
203         },
204         .set_crop = &pas202bca_set_crop,
205         .pix_format = {
206                 .width = 640,
207                 .height = 480,
208                 .pixelformat = V4L2_PIX_FMT_SBGGR8,
209                 .priv = 8,
210         },
211         .set_pix_format = &pas202bca_set_pix_format
212 };
213
214
215 int sn9c102_probe_pas202bca(struct sn9c102_device* cam)
216 {
217         const struct usb_device_id pas202bca_id_table[] = {
218                 { USB_DEVICE(0x0c45, 0x60af), },
219                 { }
220         };
221         int err = 0;
222
223         if (!sn9c102_match_id(cam,pas202bca_id_table))
224                 return -ENODEV;
225
226         err += sn9c102_write_reg(cam, 0x01, 0x01);
227         err += sn9c102_write_reg(cam, 0x40, 0x01);
228         err += sn9c102_write_reg(cam, 0x28, 0x17);
229         if (err)
230                 return -EIO;
231
232         if (sn9c102_i2c_try_write(cam, &pas202bca, 0x10, 0)) /* try to write */
233                 return -ENODEV;
234
235         sn9c102_attach_sensor(cam, &pas202bca);
236
237         return 0;
238 }