Merge branch 'omap-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind...
[pandora-kernel.git] / drivers / media / video / sn9c102 / sn9c102_hv7131d.c
1 /***************************************************************************
2  * Plug-in for HV7131D image sensor connected to the SN9C1xx PC Camera     *
3  * Controllers                                                             *
4  *                                                                         *
5  * Copyright (C) 2004-2007 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 "sn9c102_sensor.h"
23 #include "sn9c102_devtable.h"
24
25
26 static int hv7131d_init(struct sn9c102_device* cam)
27 {
28         int err;
29
30         err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11},
31                                        {0x00, 0x14}, {0x60, 0x17},
32                                        {0x0e, 0x18}, {0xf2, 0x19});
33
34         err += sn9c102_i2c_write(cam, 0x01, 0x04);
35         err += sn9c102_i2c_write(cam, 0x02, 0x00);
36         err += sn9c102_i2c_write(cam, 0x28, 0x00);
37
38         return err;
39 }
40
41
42 static int hv7131d_get_ctrl(struct sn9c102_device* cam,
43                             struct v4l2_control* ctrl)
44 {
45         switch (ctrl->id) {
46         case V4L2_CID_EXPOSURE:
47                 {
48                         int r1 = sn9c102_i2c_read(cam, 0x26),
49                             r2 = sn9c102_i2c_read(cam, 0x27);
50                         if (r1 < 0 || r2 < 0)
51                                 return -EIO;
52                         ctrl->value = (r1 << 8) | (r2 & 0xff);
53                 }
54                 return 0;
55         case V4L2_CID_RED_BALANCE:
56                 if ((ctrl->value = sn9c102_i2c_read(cam, 0x31)) < 0)
57                         return -EIO;
58                 ctrl->value = 0x3f - (ctrl->value & 0x3f);
59                 return 0;
60         case V4L2_CID_BLUE_BALANCE:
61                 if ((ctrl->value = sn9c102_i2c_read(cam, 0x33)) < 0)
62                         return -EIO;
63                 ctrl->value = 0x3f - (ctrl->value & 0x3f);
64                 return 0;
65         case SN9C102_V4L2_CID_GREEN_BALANCE:
66                 if ((ctrl->value = sn9c102_i2c_read(cam, 0x32)) < 0)
67                         return -EIO;
68                 ctrl->value = 0x3f - (ctrl->value & 0x3f);
69                 return 0;
70         case SN9C102_V4L2_CID_RESET_LEVEL:
71                 if ((ctrl->value = sn9c102_i2c_read(cam, 0x30)) < 0)
72                         return -EIO;
73                 ctrl->value &= 0x3f;
74                 return 0;
75         case SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE:
76                 if ((ctrl->value = sn9c102_i2c_read(cam, 0x34)) < 0)
77                         return -EIO;
78                 ctrl->value &= 0x07;
79                 return 0;
80         default:
81                 return -EINVAL;
82         }
83 }
84
85
86 static int hv7131d_set_ctrl(struct sn9c102_device* cam,
87                             const struct v4l2_control* ctrl)
88 {
89         int err = 0;
90
91         switch (ctrl->id) {
92         case V4L2_CID_EXPOSURE:
93                 err += sn9c102_i2c_write(cam, 0x26, ctrl->value >> 8);
94                 err += sn9c102_i2c_write(cam, 0x27, ctrl->value & 0xff);
95                 break;
96         case V4L2_CID_RED_BALANCE:
97                 err += sn9c102_i2c_write(cam, 0x31, 0x3f - ctrl->value);
98                 break;
99         case V4L2_CID_BLUE_BALANCE:
100                 err += sn9c102_i2c_write(cam, 0x33, 0x3f - ctrl->value);
101                 break;
102         case SN9C102_V4L2_CID_GREEN_BALANCE:
103                 err += sn9c102_i2c_write(cam, 0x32, 0x3f - ctrl->value);
104                 break;
105         case SN9C102_V4L2_CID_RESET_LEVEL:
106                 err += sn9c102_i2c_write(cam, 0x30, ctrl->value);
107                 break;
108         case SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE:
109                 err += sn9c102_i2c_write(cam, 0x34, ctrl->value);
110                 break;
111         default:
112                 return -EINVAL;
113         }
114
115         return err ? -EIO : 0;
116 }
117
118
119 static int hv7131d_set_crop(struct sn9c102_device* cam,
120                             const struct v4l2_rect* rect)
121 {
122         struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
123         int err = 0;
124         u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 2,
125            v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2;
126
127         err += sn9c102_write_reg(cam, h_start, 0x12);
128         err += sn9c102_write_reg(cam, v_start, 0x13);
129
130         return err;
131 }
132
133
134 static int hv7131d_set_pix_format(struct sn9c102_device* cam,
135                                   const struct v4l2_pix_format* pix)
136 {
137         int err = 0;
138
139         if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
140                 err += sn9c102_write_reg(cam, 0x42, 0x19);
141         else
142                 err += sn9c102_write_reg(cam, 0xf2, 0x19);
143
144         return err;
145 }
146
147
148 static const struct sn9c102_sensor hv7131d = {
149         .name = "HV7131D",
150         .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
151         .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102,
152         .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
153         .frequency = SN9C102_I2C_100KHZ,
154         .interface = SN9C102_I2C_2WIRES,
155         .i2c_slave_id = 0x11,
156         .init = &hv7131d_init,
157         .qctrl = {
158                 {
159                         .id = V4L2_CID_EXPOSURE,
160                         .type = V4L2_CTRL_TYPE_INTEGER,
161                         .name = "exposure",
162                         .minimum = 0x0250,
163                         .maximum = 0xffff,
164                         .step = 0x0001,
165                         .default_value = 0x0250,
166                         .flags = 0,
167                 },
168                 {
169                         .id = V4L2_CID_RED_BALANCE,
170                         .type = V4L2_CTRL_TYPE_INTEGER,
171                         .name = "red balance",
172                         .minimum = 0x00,
173                         .maximum = 0x3f,
174                         .step = 0x01,
175                         .default_value = 0x00,
176                         .flags = 0,
177                 },
178                 {
179                         .id = V4L2_CID_BLUE_BALANCE,
180                         .type = V4L2_CTRL_TYPE_INTEGER,
181                         .name = "blue balance",
182                         .minimum = 0x00,
183                         .maximum = 0x3f,
184                         .step = 0x01,
185                         .default_value = 0x20,
186                         .flags = 0,
187                 },
188                 {
189                         .id = SN9C102_V4L2_CID_GREEN_BALANCE,
190                         .type = V4L2_CTRL_TYPE_INTEGER,
191                         .name = "green balance",
192                         .minimum = 0x00,
193                         .maximum = 0x3f,
194                         .step = 0x01,
195                         .default_value = 0x1e,
196                         .flags = 0,
197                 },
198                 {
199                         .id = SN9C102_V4L2_CID_RESET_LEVEL,
200                         .type = V4L2_CTRL_TYPE_INTEGER,
201                         .name = "reset level",
202                         .minimum = 0x19,
203                         .maximum = 0x3f,
204                         .step = 0x01,
205                         .default_value = 0x30,
206                         .flags = 0,
207                 },
208                 {
209                         .id = SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE,
210                         .type = V4L2_CTRL_TYPE_INTEGER,
211                         .name = "pixel bias voltage",
212                         .minimum = 0x00,
213                         .maximum = 0x07,
214                         .step = 0x01,
215                         .default_value = 0x02,
216                         .flags = 0,
217                 },
218         },
219         .get_ctrl = &hv7131d_get_ctrl,
220         .set_ctrl = &hv7131d_set_ctrl,
221         .cropcap = {
222                 .bounds = {
223                         .left = 0,
224                         .top = 0,
225                         .width = 640,
226                         .height = 480,
227                 },
228                 .defrect = {
229                         .left = 0,
230                         .top = 0,
231                         .width = 640,
232                         .height = 480,
233                 },
234         },
235         .set_crop = &hv7131d_set_crop,
236         .pix_format = {
237                 .width = 640,
238                 .height = 480,
239                 .pixelformat = V4L2_PIX_FMT_SBGGR8,
240                 .priv = 8,
241         },
242         .set_pix_format = &hv7131d_set_pix_format
243 };
244
245
246 int sn9c102_probe_hv7131d(struct sn9c102_device* cam)
247 {
248         int r0 = 0, r1 = 0, err;
249
250         err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01},
251                                        {0x28, 0x17});
252
253         r0 = sn9c102_i2c_try_read(cam, &hv7131d, 0x00);
254         r1 = sn9c102_i2c_try_read(cam, &hv7131d, 0x01);
255         if (err || r0 < 0 || r1 < 0)
256                 return -EIO;
257
258         if ((r0 != 0x00 && r0 != 0x01) || r1 != 0x04)
259                 return -ENODEV;
260
261         sn9c102_attach_sensor(cam, &hv7131d);
262
263         return 0;
264 }