aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/ovcamchip
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/media/video/ovcamchip
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'drivers/media/video/ovcamchip')
-rw-r--r--drivers/media/video/ovcamchip/Makefile4
-rw-r--r--drivers/media/video/ovcamchip/ov6x20.c415
-rw-r--r--drivers/media/video/ovcamchip/ov6x30.c374
-rw-r--r--drivers/media/video/ovcamchip/ov76be.c303
-rw-r--r--drivers/media/video/ovcamchip/ov7x10.c335
-rw-r--r--drivers/media/video/ovcamchip/ov7x20.c455
-rw-r--r--drivers/media/video/ovcamchip/ovcamchip_core.c444
-rw-r--r--drivers/media/video/ovcamchip/ovcamchip_priv.h87
8 files changed, 2417 insertions, 0 deletions
diff --git a/drivers/media/video/ovcamchip/Makefile b/drivers/media/video/ovcamchip/Makefile
new file mode 100644
index 000000000000..bca41ad93de8
--- /dev/null
+++ b/drivers/media/video/ovcamchip/Makefile
@@ -0,0 +1,4 @@
1ovcamchip-objs := ovcamchip_core.o ov6x20.o ov6x30.o ov7x10.o ov7x20.o \
2 ov76be.o
3
4obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip.o
diff --git a/drivers/media/video/ovcamchip/ov6x20.c b/drivers/media/video/ovcamchip/ov6x20.c
new file mode 100644
index 000000000000..3433619ad93f
--- /dev/null
+++ b/drivers/media/video/ovcamchip/ov6x20.c
@@ -0,0 +1,415 @@
1/* OmniVision OV6620/OV6120 Camera Chip Support Code
2 *
3 * Copyright (c) 1999-2004 Mark McClelland <mark@alpha.dyndns.org>
4 * http://alpha.dyndns.org/ov511/
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. NO WARRANTY OF ANY KIND is expressed or implied.
10 */
11
12#define DEBUG
13
14#include <linux/slab.h>
15#include "ovcamchip_priv.h"
16
17/* Registers */
18#define REG_GAIN 0x00 /* gain [5:0] */
19#define REG_BLUE 0x01 /* blue gain */
20#define REG_RED 0x02 /* red gain */
21#define REG_SAT 0x03 /* saturation */
22#define REG_CNT 0x05 /* Y contrast */
23#define REG_BRT 0x06 /* Y brightness */
24#define REG_WB_BLUE 0x0C /* WB blue ratio [5:0] */
25#define REG_WB_RED 0x0D /* WB red ratio [5:0] */
26#define REG_EXP 0x10 /* exposure */
27
28/* Window parameters */
29#define HWSBASE 0x38
30#define HWEBASE 0x3A
31#define VWSBASE 0x05
32#define VWEBASE 0x06
33
34struct ov6x20 {
35 int auto_brt;
36 int auto_exp;
37 int backlight;
38 int bandfilt;
39 int mirror;
40};
41
42/* Initial values for use with OV511/OV511+ cameras */
43static struct ovcamchip_regvals regvals_init_6x20_511[] = {
44 { 0x12, 0x80 }, /* reset */
45 { 0x11, 0x01 },
46 { 0x03, 0x60 },
47 { 0x05, 0x7f }, /* For when autoadjust is off */
48 { 0x07, 0xa8 },
49 { 0x0c, 0x24 },
50 { 0x0d, 0x24 },
51 { 0x0f, 0x15 }, /* COMS */
52 { 0x10, 0x75 }, /* AEC Exposure time */
53 { 0x12, 0x24 }, /* Enable AGC and AWB */
54 { 0x14, 0x04 },
55 { 0x16, 0x03 },
56 { 0x26, 0xb2 }, /* BLC enable */
57 /* 0x28: 0x05 Selects RGB format if RGB on */
58 { 0x28, 0x05 },
59 { 0x2a, 0x04 }, /* Disable framerate adjust */
60 { 0x2d, 0x99 },
61 { 0x33, 0xa0 }, /* Color Processing Parameter */
62 { 0x34, 0xd2 }, /* Max A/D range */
63 { 0x38, 0x8b },
64 { 0x39, 0x40 },
65
66 { 0x3c, 0x39 }, /* Enable AEC mode changing */
67 { 0x3c, 0x3c }, /* Change AEC mode */
68 { 0x3c, 0x24 }, /* Disable AEC mode changing */
69
70 { 0x3d, 0x80 },
71 /* These next two registers (0x4a, 0x4b) are undocumented. They
72 * control the color balance */
73 { 0x4a, 0x80 },
74 { 0x4b, 0x80 },
75 { 0x4d, 0xd2 }, /* This reduces noise a bit */
76 { 0x4e, 0xc1 },
77 { 0x4f, 0x04 },
78 { 0xff, 0xff }, /* END MARKER */
79};
80
81/* Initial values for use with OV518 cameras */
82static struct ovcamchip_regvals regvals_init_6x20_518[] = {
83 { 0x12, 0x80 }, /* Do a reset */
84 { 0x03, 0xc0 }, /* Saturation */
85 { 0x05, 0x8a }, /* Contrast */
86 { 0x0c, 0x24 }, /* AWB blue */
87 { 0x0d, 0x24 }, /* AWB red */
88 { 0x0e, 0x8d }, /* Additional 2x gain */
89 { 0x0f, 0x25 }, /* Black expanding level = 1.3V */
90 { 0x11, 0x01 }, /* Clock div. */
91 { 0x12, 0x24 }, /* Enable AGC and AWB */
92 { 0x13, 0x01 }, /* (default) */
93 { 0x14, 0x80 }, /* Set reserved bit 7 */
94 { 0x15, 0x01 }, /* (default) */
95 { 0x16, 0x03 }, /* (default) */
96 { 0x17, 0x38 }, /* (default) */
97 { 0x18, 0xea }, /* (default) */
98 { 0x19, 0x04 },
99 { 0x1a, 0x93 },
100 { 0x1b, 0x00 }, /* (default) */
101 { 0x1e, 0xc4 }, /* (default) */
102 { 0x1f, 0x04 }, /* (default) */
103 { 0x20, 0x20 }, /* Enable 1st stage aperture correction */
104 { 0x21, 0x10 }, /* Y offset */
105 { 0x22, 0x88 }, /* U offset */
106 { 0x23, 0xc0 }, /* Set XTAL power level */
107 { 0x24, 0x53 }, /* AEC bright ratio */
108 { 0x25, 0x7a }, /* AEC black ratio */
109 { 0x26, 0xb2 }, /* BLC enable */
110 { 0x27, 0xa2 }, /* Full output range */
111 { 0x28, 0x01 }, /* (default) */
112 { 0x29, 0x00 }, /* (default) */
113 { 0x2a, 0x84 }, /* (default) */
114 { 0x2b, 0xa8 }, /* Set custom frame rate */
115 { 0x2c, 0xa0 }, /* (reserved) */
116 { 0x2d, 0x95 }, /* Enable banding filter */
117 { 0x2e, 0x88 }, /* V offset */
118 { 0x33, 0x22 }, /* Luminance gamma on */
119 { 0x34, 0xc7 }, /* A/D bias */
120 { 0x36, 0x12 }, /* (reserved) */
121 { 0x37, 0x63 }, /* (reserved) */
122 { 0x38, 0x8b }, /* Quick AEC/AEB */
123 { 0x39, 0x00 }, /* (default) */
124 { 0x3a, 0x0f }, /* (default) */
125 { 0x3b, 0x3c }, /* (default) */
126 { 0x3c, 0x5c }, /* AEC controls */
127 { 0x3d, 0x80 }, /* Drop 1 (bad) frame when AEC change */
128 { 0x3e, 0x80 }, /* (default) */
129 { 0x3f, 0x02 }, /* (default) */
130 { 0x40, 0x10 }, /* (reserved) */
131 { 0x41, 0x10 }, /* (reserved) */
132 { 0x42, 0x00 }, /* (reserved) */
133 { 0x43, 0x7f }, /* (reserved) */
134 { 0x44, 0x80 }, /* (reserved) */
135 { 0x45, 0x1c }, /* (reserved) */
136 { 0x46, 0x1c }, /* (reserved) */
137 { 0x47, 0x80 }, /* (reserved) */
138 { 0x48, 0x5f }, /* (reserved) */
139 { 0x49, 0x00 }, /* (reserved) */
140 { 0x4a, 0x00 }, /* Color balance (undocumented) */
141 { 0x4b, 0x80 }, /* Color balance (undocumented) */
142 { 0x4c, 0x58 }, /* (reserved) */
143 { 0x4d, 0xd2 }, /* U *= .938, V *= .838 */
144 { 0x4e, 0xa0 }, /* (default) */
145 { 0x4f, 0x04 }, /* UV 3-point average */
146 { 0x50, 0xff }, /* (reserved) */
147 { 0x51, 0x58 }, /* (reserved) */
148 { 0x52, 0xc0 }, /* (reserved) */
149 { 0x53, 0x42 }, /* (reserved) */
150 { 0x27, 0xa6 }, /* Enable manual offset adj. (reg 21 & 22) */
151 { 0x12, 0x20 },
152 { 0x12, 0x24 },
153
154 { 0xff, 0xff }, /* END MARKER */
155};
156
157/* This initializes the OV6x20 camera chip and relevant variables. */
158static int ov6x20_init(struct i2c_client *c)
159{
160 struct ovcamchip *ov = i2c_get_clientdata(c);
161 struct ov6x20 *s;
162 int rc;
163
164 DDEBUG(4, &c->dev, "entered");
165
166 switch (c->adapter->id) {
167 case I2C_ALGO_SMBUS | I2C_HW_SMBUS_OV511:
168 rc = ov_write_regvals(c, regvals_init_6x20_511);
169 break;
170 case I2C_ALGO_SMBUS | I2C_HW_SMBUS_OV518:
171 rc = ov_write_regvals(c, regvals_init_6x20_518);
172 break;
173 default:
174 dev_err(&c->dev, "ov6x20: Unsupported adapter\n");
175 rc = -ENODEV;
176 }
177
178 if (rc < 0)
179 return rc;
180
181 ov->spriv = s = kmalloc(sizeof *s, GFP_KERNEL);
182 if (!s)
183 return -ENOMEM;
184 memset(s, 0, sizeof *s);
185
186 s->auto_brt = 1;
187 s->auto_exp = 1;
188
189 return rc;
190}
191
192static int ov6x20_free(struct i2c_client *c)
193{
194 struct ovcamchip *ov = i2c_get_clientdata(c);
195
196 kfree(ov->spriv);
197 return 0;
198}
199
200static int ov6x20_set_control(struct i2c_client *c,
201 struct ovcamchip_control *ctl)
202{
203 struct ovcamchip *ov = i2c_get_clientdata(c);
204 struct ov6x20 *s = ov->spriv;
205 int rc;
206 int v = ctl->value;
207
208 switch (ctl->id) {
209 case OVCAMCHIP_CID_CONT:
210 rc = ov_write(c, REG_CNT, v >> 8);
211 break;
212 case OVCAMCHIP_CID_BRIGHT:
213 rc = ov_write(c, REG_BRT, v >> 8);
214 break;
215 case OVCAMCHIP_CID_SAT:
216 rc = ov_write(c, REG_SAT, v >> 8);
217 break;
218 case OVCAMCHIP_CID_HUE:
219 rc = ov_write(c, REG_RED, 0xFF - (v >> 8));
220 if (rc < 0)
221 goto out;
222
223 rc = ov_write(c, REG_BLUE, v >> 8);
224 break;
225 case OVCAMCHIP_CID_EXP:
226 rc = ov_write(c, REG_EXP, v);
227 break;
228 case OVCAMCHIP_CID_FREQ:
229 {
230 int sixty = (v == 60);
231
232 rc = ov_write(c, 0x2b, sixty?0xa8:0x28);
233 if (rc < 0)
234 goto out;
235
236 rc = ov_write(c, 0x2a, sixty?0x84:0xa4);
237 break;
238 }
239 case OVCAMCHIP_CID_BANDFILT:
240 rc = ov_write_mask(c, 0x2d, v?0x04:0x00, 0x04);
241 s->bandfilt = v;
242 break;
243 case OVCAMCHIP_CID_AUTOBRIGHT:
244 rc = ov_write_mask(c, 0x2d, v?0x10:0x00, 0x10);
245 s->auto_brt = v;
246 break;
247 case OVCAMCHIP_CID_AUTOEXP:
248 rc = ov_write_mask(c, 0x13, v?0x01:0x00, 0x01);
249 s->auto_exp = v;
250 break;
251 case OVCAMCHIP_CID_BACKLIGHT:
252 {
253 rc = ov_write_mask(c, 0x4e, v?0xe0:0xc0, 0xe0);
254 if (rc < 0)
255 goto out;
256
257 rc = ov_write_mask(c, 0x29, v?0x08:0x00, 0x08);
258 if (rc < 0)
259 goto out;
260
261 rc = ov_write_mask(c, 0x0e, v?0x80:0x00, 0x80);
262 s->backlight = v;
263 break;
264 }
265 case OVCAMCHIP_CID_MIRROR:
266 rc = ov_write_mask(c, 0x12, v?0x40:0x00, 0x40);
267 s->mirror = v;
268 break;
269 default:
270 DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
271 return -EPERM;
272 }
273
274out:
275 DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, v, rc);
276 return rc;
277}
278
279static int ov6x20_get_control(struct i2c_client *c,
280 struct ovcamchip_control *ctl)
281{
282 struct ovcamchip *ov = i2c_get_clientdata(c);
283 struct ov6x20 *s = ov->spriv;
284 int rc = 0;
285 unsigned char val = 0;
286
287 switch (ctl->id) {
288 case OVCAMCHIP_CID_CONT:
289 rc = ov_read(c, REG_CNT, &val);
290 ctl->value = val << 8;
291 break;
292 case OVCAMCHIP_CID_BRIGHT:
293 rc = ov_read(c, REG_BRT, &val);
294 ctl->value = val << 8;
295 break;
296 case OVCAMCHIP_CID_SAT:
297 rc = ov_read(c, REG_SAT, &val);
298 ctl->value = val << 8;
299 break;
300 case OVCAMCHIP_CID_HUE:
301 rc = ov_read(c, REG_BLUE, &val);
302 ctl->value = val << 8;
303 break;
304 case OVCAMCHIP_CID_EXP:
305 rc = ov_read(c, REG_EXP, &val);
306 ctl->value = val;
307 break;
308 case OVCAMCHIP_CID_BANDFILT:
309 ctl->value = s->bandfilt;
310 break;
311 case OVCAMCHIP_CID_AUTOBRIGHT:
312 ctl->value = s->auto_brt;
313 break;
314 case OVCAMCHIP_CID_AUTOEXP:
315 ctl->value = s->auto_exp;
316 break;
317 case OVCAMCHIP_CID_BACKLIGHT:
318 ctl->value = s->backlight;
319 break;
320 case OVCAMCHIP_CID_MIRROR:
321 ctl->value = s->mirror;
322 break;
323 default:
324 DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
325 return -EPERM;
326 }
327
328 DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, ctl->value, rc);
329 return rc;
330}
331
332static int ov6x20_mode_init(struct i2c_client *c, struct ovcamchip_window *win)
333{
334 /******** QCIF-specific regs ********/
335
336 ov_write(c, 0x14, win->quarter?0x24:0x04);
337
338 /******** Palette-specific regs ********/
339
340 /* OV518 needs 8 bit multiplexed in color mode, and 16 bit in B&W */
341 if (c->adapter->id == (I2C_ALGO_SMBUS | I2C_HW_SMBUS_OV518)) {
342 if (win->format == VIDEO_PALETTE_GREY)
343 ov_write_mask(c, 0x13, 0x00, 0x20);
344 else
345 ov_write_mask(c, 0x13, 0x20, 0x20);
346 } else {
347 if (win->format == VIDEO_PALETTE_GREY)
348 ov_write_mask(c, 0x13, 0x20, 0x20);
349 else
350 ov_write_mask(c, 0x13, 0x00, 0x20);
351 }
352
353 /******** Clock programming ********/
354
355 /* The OV6620 needs special handling. This prevents the
356 * severe banding that normally occurs */
357
358 /* Clock down */
359 ov_write(c, 0x2a, 0x04);
360
361 ov_write(c, 0x11, win->clockdiv);
362
363 ov_write(c, 0x2a, 0x84);
364 /* This next setting is critical. It seems to improve
365 * the gain or the contrast. The "reserved" bits seem
366 * to have some effect in this case. */
367 ov_write(c, 0x2d, 0x85); /* FIXME: This messes up banding filter */
368
369 return 0;
370}
371
372static int ov6x20_set_window(struct i2c_client *c, struct ovcamchip_window *win)
373{
374 int ret, hwscale, vwscale;
375
376 ret = ov6x20_mode_init(c, win);
377 if (ret < 0)
378 return ret;
379
380 if (win->quarter) {
381 hwscale = 0;
382 vwscale = 0;
383 } else {
384 hwscale = 1;
385 vwscale = 1; /* The datasheet says 0; it's wrong */
386 }
387
388 ov_write(c, 0x17, HWSBASE + (win->x >> hwscale));
389 ov_write(c, 0x18, HWEBASE + ((win->x + win->width) >> hwscale));
390 ov_write(c, 0x19, VWSBASE + (win->y >> vwscale));
391 ov_write(c, 0x1a, VWEBASE + ((win->y + win->height) >> vwscale));
392
393 return 0;
394}
395
396static int ov6x20_command(struct i2c_client *c, unsigned int cmd, void *arg)
397{
398 switch (cmd) {
399 case OVCAMCHIP_CMD_S_CTRL:
400 return ov6x20_set_control(c, arg);
401 case OVCAMCHIP_CMD_G_CTRL:
402 return ov6x20_get_control(c, arg);
403 case OVCAMCHIP_CMD_S_MODE:
404 return ov6x20_set_window(c, arg);
405 default:
406 DDEBUG(2, &c->dev, "command not supported: %d", cmd);
407 return -ENOIOCTLCMD;
408 }
409}
410
411struct ovcamchip_ops ov6x20_ops = {
412 .init = ov6x20_init,
413 .free = ov6x20_free,
414 .command = ov6x20_command,
415};
diff --git a/drivers/media/video/ovcamchip/ov6x30.c b/drivers/media/video/ovcamchip/ov6x30.c
new file mode 100644
index 000000000000..44a842379b45
--- /dev/null
+++ b/drivers/media/video/ovcamchip/ov6x30.c
@@ -0,0 +1,374 @@
1/* OmniVision OV6630/OV6130 Camera Chip Support Code
2 *
3 * Copyright (c) 1999-2004 Mark McClelland <mark@alpha.dyndns.org>
4 * http://alpha.dyndns.org/ov511/
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. NO WARRANTY OF ANY KIND is expressed or implied.
10 */
11
12#define DEBUG
13
14#include <linux/slab.h>
15#include "ovcamchip_priv.h"
16
17/* Registers */
18#define REG_GAIN 0x00 /* gain [5:0] */
19#define REG_BLUE 0x01 /* blue gain */
20#define REG_RED 0x02 /* red gain */
21#define REG_SAT 0x03 /* saturation [7:3] */
22#define REG_CNT 0x05 /* Y contrast [3:0] */
23#define REG_BRT 0x06 /* Y brightness */
24#define REG_SHARP 0x07 /* sharpness */
25#define REG_WB_BLUE 0x0C /* WB blue ratio [5:0] */
26#define REG_WB_RED 0x0D /* WB red ratio [5:0] */
27#define REG_EXP 0x10 /* exposure */
28
29/* Window parameters */
30#define HWSBASE 0x38
31#define HWEBASE 0x3A
32#define VWSBASE 0x05
33#define VWEBASE 0x06
34
35struct ov6x30 {
36 int auto_brt;
37 int auto_exp;
38 int backlight;
39 int bandfilt;
40 int mirror;
41};
42
43static struct ovcamchip_regvals regvals_init_6x30[] = {
44 { 0x12, 0x80 }, /* reset */
45 { 0x00, 0x1f }, /* Gain */
46 { 0x01, 0x99 }, /* Blue gain */
47 { 0x02, 0x7c }, /* Red gain */
48 { 0x03, 0xc0 }, /* Saturation */
49 { 0x05, 0x0a }, /* Contrast */
50 { 0x06, 0x95 }, /* Brightness */
51 { 0x07, 0x2d }, /* Sharpness */
52 { 0x0c, 0x20 },
53 { 0x0d, 0x20 },
54 { 0x0e, 0x20 },
55 { 0x0f, 0x05 },
56 { 0x10, 0x9a }, /* "exposure check" */
57 { 0x11, 0x00 }, /* Pixel clock = fastest */
58 { 0x12, 0x24 }, /* Enable AGC and AWB */
59 { 0x13, 0x21 },
60 { 0x14, 0x80 },
61 { 0x15, 0x01 },
62 { 0x16, 0x03 },
63 { 0x17, 0x38 },
64 { 0x18, 0xea },
65 { 0x19, 0x04 },
66 { 0x1a, 0x93 },
67 { 0x1b, 0x00 },
68 { 0x1e, 0xc4 },
69 { 0x1f, 0x04 },
70 { 0x20, 0x20 },
71 { 0x21, 0x10 },
72 { 0x22, 0x88 },
73 { 0x23, 0xc0 }, /* Crystal circuit power level */
74 { 0x25, 0x9a }, /* Increase AEC black pixel ratio */
75 { 0x26, 0xb2 }, /* BLC enable */
76 { 0x27, 0xa2 },
77 { 0x28, 0x00 },
78 { 0x29, 0x00 },
79 { 0x2a, 0x84 }, /* (keep) */
80 { 0x2b, 0xa8 }, /* (keep) */
81 { 0x2c, 0xa0 },
82 { 0x2d, 0x95 }, /* Enable auto-brightness */
83 { 0x2e, 0x88 },
84 { 0x33, 0x26 },
85 { 0x34, 0x03 },
86 { 0x36, 0x8f },
87 { 0x37, 0x80 },
88 { 0x38, 0x83 },
89 { 0x39, 0x80 },
90 { 0x3a, 0x0f },
91 { 0x3b, 0x3c },
92 { 0x3c, 0x1a },
93 { 0x3d, 0x80 },
94 { 0x3e, 0x80 },
95 { 0x3f, 0x0e },
96 { 0x40, 0x00 }, /* White bal */
97 { 0x41, 0x00 }, /* White bal */
98 { 0x42, 0x80 },
99 { 0x43, 0x3f }, /* White bal */
100 { 0x44, 0x80 },
101 { 0x45, 0x20 },
102 { 0x46, 0x20 },
103 { 0x47, 0x80 },
104 { 0x48, 0x7f },
105 { 0x49, 0x00 },
106 { 0x4a, 0x00 },
107 { 0x4b, 0x80 },
108 { 0x4c, 0xd0 },
109 { 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */
110 { 0x4e, 0x40 },
111 { 0x4f, 0x07 }, /* UV average mode, color killer: strongest */
112 { 0x50, 0xff },
113 { 0x54, 0x23 }, /* Max AGC gain: 18dB */
114 { 0x55, 0xff },
115 { 0x56, 0x12 },
116 { 0x57, 0x81 }, /* (default) */
117 { 0x58, 0x75 },
118 { 0x59, 0x01 }, /* AGC dark current compensation: +1 */
119 { 0x5a, 0x2c },
120 { 0x5b, 0x0f }, /* AWB chrominance levels */
121 { 0x5c, 0x10 },
122 { 0x3d, 0x80 },
123 { 0x27, 0xa6 },
124 /* Toggle AWB off and on */
125 { 0x12, 0x20 },
126 { 0x12, 0x24 },
127
128 { 0xff, 0xff }, /* END MARKER */
129};
130
131/* This initializes the OV6x30 camera chip and relevant variables. */
132static int ov6x30_init(struct i2c_client *c)
133{
134 struct ovcamchip *ov = i2c_get_clientdata(c);
135 struct ov6x30 *s;
136 int rc;
137
138 DDEBUG(4, &c->dev, "entered");
139
140 rc = ov_write_regvals(c, regvals_init_6x30);
141 if (rc < 0)
142 return rc;
143
144 ov->spriv = s = kmalloc(sizeof *s, GFP_KERNEL);
145 if (!s)
146 return -ENOMEM;
147 memset(s, 0, sizeof *s);
148
149 s->auto_brt = 1;
150 s->auto_exp = 1;
151
152 return rc;
153}
154
155static int ov6x30_free(struct i2c_client *c)
156{
157 struct ovcamchip *ov = i2c_get_clientdata(c);
158
159 kfree(ov->spriv);
160 return 0;
161}
162
163static int ov6x30_set_control(struct i2c_client *c,
164 struct ovcamchip_control *ctl)
165{
166 struct ovcamchip *ov = i2c_get_clientdata(c);
167 struct ov6x30 *s = ov->spriv;
168 int rc;
169 int v = ctl->value;
170
171 switch (ctl->id) {
172 case OVCAMCHIP_CID_CONT:
173 rc = ov_write_mask(c, REG_CNT, v >> 12, 0x0f);
174 break;
175 case OVCAMCHIP_CID_BRIGHT:
176 rc = ov_write(c, REG_BRT, v >> 8);
177 break;
178 case OVCAMCHIP_CID_SAT:
179 rc = ov_write(c, REG_SAT, v >> 8);
180 break;
181 case OVCAMCHIP_CID_HUE:
182 rc = ov_write(c, REG_RED, 0xFF - (v >> 8));
183 if (rc < 0)
184 goto out;
185
186 rc = ov_write(c, REG_BLUE, v >> 8);
187 break;
188 case OVCAMCHIP_CID_EXP:
189 rc = ov_write(c, REG_EXP, v);
190 break;
191 case OVCAMCHIP_CID_FREQ:
192 {
193 int sixty = (v == 60);
194
195 rc = ov_write(c, 0x2b, sixty?0xa8:0x28);
196 if (rc < 0)
197 goto out;
198
199 rc = ov_write(c, 0x2a, sixty?0x84:0xa4);
200 break;
201 }
202 case OVCAMCHIP_CID_BANDFILT:
203 rc = ov_write_mask(c, 0x2d, v?0x04:0x00, 0x04);
204 s->bandfilt = v;
205 break;
206 case OVCAMCHIP_CID_AUTOBRIGHT:
207 rc = ov_write_mask(c, 0x2d, v?0x10:0x00, 0x10);
208 s->auto_brt = v;
209 break;
210 case OVCAMCHIP_CID_AUTOEXP:
211 rc = ov_write_mask(c, 0x28, v?0x00:0x10, 0x10);
212 s->auto_exp = v;
213 break;
214 case OVCAMCHIP_CID_BACKLIGHT:
215 {
216 rc = ov_write_mask(c, 0x4e, v?0x80:0x60, 0xe0);
217 if (rc < 0)
218 goto out;
219
220 rc = ov_write_mask(c, 0x29, v?0x08:0x00, 0x08);
221 if (rc < 0)
222 goto out;
223
224 rc = ov_write_mask(c, 0x28, v?0x02:0x00, 0x02);
225 s->backlight = v;
226 break;
227 }
228 case OVCAMCHIP_CID_MIRROR:
229 rc = ov_write_mask(c, 0x12, v?0x40:0x00, 0x40);
230 s->mirror = v;
231 break;
232 default:
233 DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
234 return -EPERM;
235 }
236
237out:
238 DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, v, rc);
239 return rc;
240}
241
242static int ov6x30_get_control(struct i2c_client *c,
243 struct ovcamchip_control *ctl)
244{
245 struct ovcamchip *ov = i2c_get_clientdata(c);
246 struct ov6x30 *s = ov->spriv;
247 int rc = 0;
248 unsigned char val = 0;
249
250 switch (ctl->id) {
251 case OVCAMCHIP_CID_CONT:
252 rc = ov_read(c, REG_CNT, &val);
253 ctl->value = (val & 0x0f) << 12;
254 break;
255 case OVCAMCHIP_CID_BRIGHT:
256 rc = ov_read(c, REG_BRT, &val);
257 ctl->value = val << 8;
258 break;
259 case OVCAMCHIP_CID_SAT:
260 rc = ov_read(c, REG_SAT, &val);
261 ctl->value = val << 8;
262 break;
263 case OVCAMCHIP_CID_HUE:
264 rc = ov_read(c, REG_BLUE, &val);
265 ctl->value = val << 8;
266 break;
267 case OVCAMCHIP_CID_EXP:
268 rc = ov_read(c, REG_EXP, &val);
269 ctl->value = val;
270 break;
271 case OVCAMCHIP_CID_BANDFILT:
272 ctl->value = s->bandfilt;
273 break;
274 case OVCAMCHIP_CID_AUTOBRIGHT:
275 ctl->value = s->auto_brt;
276 break;
277 case OVCAMCHIP_CID_AUTOEXP:
278 ctl->value = s->auto_exp;
279 break;
280 case OVCAMCHIP_CID_BACKLIGHT:
281 ctl->value = s->backlight;
282 break;
283 case OVCAMCHIP_CID_MIRROR:
284 ctl->value = s->mirror;
285 break;
286 default:
287 DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
288 return -EPERM;
289 }
290
291 DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, ctl->value, rc);
292 return rc;
293}
294
295static int ov6x30_mode_init(struct i2c_client *c, struct ovcamchip_window *win)
296{
297 /******** QCIF-specific regs ********/
298
299 ov_write_mask(c, 0x14, win->quarter?0x20:0x00, 0x20);
300
301 /******** Palette-specific regs ********/
302
303 if (win->format == VIDEO_PALETTE_GREY) {
304 if (c->adapter->id == (I2C_ALGO_SMBUS | I2C_HW_SMBUS_OV518)) {
305 /* Do nothing - we're already in 8-bit mode */
306 } else {
307 ov_write_mask(c, 0x13, 0x20, 0x20);
308 }
309 } else {
310 /* The OV518 needs special treatment. Although both the OV518
311 * and the OV6630 support a 16-bit video bus, only the 8 bit Y
312 * bus is actually used. The UV bus is tied to ground.
313 * Therefore, the OV6630 needs to be in 8-bit multiplexed
314 * output mode */
315
316 if (c->adapter->id == (I2C_ALGO_SMBUS | I2C_HW_SMBUS_OV518)) {
317 /* Do nothing - we want to stay in 8-bit mode */
318 /* Warning: Messing with reg 0x13 breaks OV518 color */
319 } else {
320 ov_write_mask(c, 0x13, 0x00, 0x20);
321 }
322 }
323
324 /******** Clock programming ********/
325
326 ov_write(c, 0x11, win->clockdiv);
327
328 return 0;
329}
330
331static int ov6x30_set_window(struct i2c_client *c, struct ovcamchip_window *win)
332{
333 int ret, hwscale, vwscale;
334
335 ret = ov6x30_mode_init(c, win);
336 if (ret < 0)
337 return ret;
338
339 if (win->quarter) {
340 hwscale = 0;
341 vwscale = 0;
342 } else {
343 hwscale = 1;
344 vwscale = 1; /* The datasheet says 0; it's wrong */
345 }
346
347 ov_write(c, 0x17, HWSBASE + (win->x >> hwscale));
348 ov_write(c, 0x18, HWEBASE + ((win->x + win->width) >> hwscale));
349 ov_write(c, 0x19, VWSBASE + (win->y >> vwscale));
350 ov_write(c, 0x1a, VWEBASE + ((win->y + win->height) >> vwscale));
351
352 return 0;
353}
354
355static int ov6x30_command(struct i2c_client *c, unsigned int cmd, void *arg)
356{
357 switch (cmd) {
358 case OVCAMCHIP_CMD_S_CTRL:
359 return ov6x30_set_control(c, arg);
360 case OVCAMCHIP_CMD_G_CTRL:
361 return ov6x30_get_control(c, arg);
362 case OVCAMCHIP_CMD_S_MODE:
363 return ov6x30_set_window(c, arg);
364 default:
365 DDEBUG(2, &c->dev, "command not supported: %d", cmd);
366 return -ENOIOCTLCMD;
367 }
368}
369
370struct ovcamchip_ops ov6x30_ops = {
371 .init = ov6x30_init,
372 .free = ov6x30_free,
373 .command = ov6x30_command,
374};
diff --git a/drivers/media/video/ovcamchip/ov76be.c b/drivers/media/video/ovcamchip/ov76be.c
new file mode 100644
index 000000000000..29bbdc05e3b6
--- /dev/null
+++ b/drivers/media/video/ovcamchip/ov76be.c
@@ -0,0 +1,303 @@
1/* OmniVision OV76BE Camera Chip Support Code
2 *
3 * Copyright (c) 1999-2004 Mark McClelland <mark@alpha.dyndns.org>
4 * http://alpha.dyndns.org/ov511/
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. NO WARRANTY OF ANY KIND is expressed or implied.
10 */
11
12#define DEBUG
13
14#include <linux/slab.h>
15#include "ovcamchip_priv.h"
16
17/* OV7610 registers: Since the OV76BE is undocumented, we'll settle for these
18 * for now. */
19#define REG_GAIN 0x00 /* gain [5:0] */
20#define REG_BLUE 0x01 /* blue channel balance */
21#define REG_RED 0x02 /* red channel balance */
22#define REG_SAT 0x03 /* saturation */
23#define REG_CNT 0x05 /* Y contrast */
24#define REG_BRT 0x06 /* Y brightness */
25#define REG_BLUE_BIAS 0x0C /* blue channel bias [5:0] */
26#define REG_RED_BIAS 0x0D /* red channel bias [5:0] */
27#define REG_GAMMA_COEFF 0x0E /* gamma settings */
28#define REG_WB_RANGE 0x0F /* AEC/ALC/S-AWB settings */
29#define REG_EXP 0x10 /* manual exposure setting */
30#define REG_CLOCK 0x11 /* polarity/clock prescaler */
31#define REG_FIELD_DIVIDE 0x16 /* field interval/mode settings */
32#define REG_HWIN_START 0x17 /* horizontal window start */
33#define REG_HWIN_END 0x18 /* horizontal window end */
34#define REG_VWIN_START 0x19 /* vertical window start */
35#define REG_VWIN_END 0x1A /* vertical window end */
36#define REG_PIXEL_SHIFT 0x1B /* pixel shift */
37#define REG_YOFFSET 0x21 /* Y channel offset */
38#define REG_UOFFSET 0x22 /* U channel offset */
39#define REG_ECW 0x24 /* exposure white level for AEC */
40#define REG_ECB 0x25 /* exposure black level for AEC */
41#define REG_FRAMERATE_H 0x2A /* frame rate MSB + misc */
42#define REG_FRAMERATE_L 0x2B /* frame rate LSB */
43#define REG_ALC 0x2C /* Auto Level Control settings */
44#define REG_VOFFSET 0x2E /* V channel offset adjustment */
45#define REG_ARRAY_BIAS 0x2F /* array bias -- don't change */
46#define REG_YGAMMA 0x33 /* misc gamma settings [7:6] */
47#define REG_BIAS_ADJUST 0x34 /* misc bias settings */
48
49/* Window parameters */
50#define HWSBASE 0x38
51#define HWEBASE 0x3a
52#define VWSBASE 0x05
53#define VWEBASE 0x05
54
55struct ov76be {
56 int auto_brt;
57 int auto_exp;
58 int bandfilt;
59 int mirror;
60};
61
62/* NOTE: These are the same as the 7x10 settings, but should eventually be
63 * optimized for the OV76BE */
64static struct ovcamchip_regvals regvals_init_76be[] = {
65 { 0x10, 0xff },
66 { 0x16, 0x03 },
67 { 0x28, 0x24 },
68 { 0x2b, 0xac },
69 { 0x12, 0x00 },
70 { 0x38, 0x81 },
71 { 0x28, 0x24 }, /* 0c */
72 { 0x0f, 0x85 }, /* lg's setting */
73 { 0x15, 0x01 },
74 { 0x20, 0x1c },
75 { 0x23, 0x2a },
76 { 0x24, 0x10 },
77 { 0x25, 0x8a },
78 { 0x26, 0xa2 },
79 { 0x27, 0xc2 },
80 { 0x2a, 0x04 },
81 { 0x2c, 0xfe },
82 { 0x2d, 0x93 },
83 { 0x30, 0x71 },
84 { 0x31, 0x60 },
85 { 0x32, 0x26 },
86 { 0x33, 0x20 },
87 { 0x34, 0x48 },
88 { 0x12, 0x24 },
89 { 0x11, 0x01 },
90 { 0x0c, 0x24 },
91 { 0x0d, 0x24 },
92 { 0xff, 0xff }, /* END MARKER */
93};
94
95/* This initializes the OV76be camera chip and relevant variables. */
96static int ov76be_init(struct i2c_client *c)
97{
98 struct ovcamchip *ov = i2c_get_clientdata(c);
99 struct ov76be *s;
100 int rc;
101
102 DDEBUG(4, &c->dev, "entered");
103
104 rc = ov_write_regvals(c, regvals_init_76be);
105 if (rc < 0)
106 return rc;
107
108 ov->spriv = s = kmalloc(sizeof *s, GFP_KERNEL);
109 if (!s)
110 return -ENOMEM;
111 memset(s, 0, sizeof *s);
112
113 s->auto_brt = 1;
114 s->auto_exp = 1;
115
116 return rc;
117}
118
119static int ov76be_free(struct i2c_client *c)
120{
121 struct ovcamchip *ov = i2c_get_clientdata(c);
122
123 kfree(ov->spriv);
124 return 0;
125}
126
127static int ov76be_set_control(struct i2c_client *c,
128 struct ovcamchip_control *ctl)
129{
130 struct ovcamchip *ov = i2c_get_clientdata(c);
131 struct ov76be *s = ov->spriv;
132 int rc;
133 int v = ctl->value;
134
135 switch (ctl->id) {
136 case OVCAMCHIP_CID_BRIGHT:
137 rc = ov_write(c, REG_BRT, v >> 8);
138 break;
139 case OVCAMCHIP_CID_SAT:
140 rc = ov_write(c, REG_SAT, v >> 8);
141 break;
142 case OVCAMCHIP_CID_EXP:
143 rc = ov_write(c, REG_EXP, v);
144 break;
145 case OVCAMCHIP_CID_FREQ:
146 {
147 int sixty = (v == 60);
148
149 rc = ov_write_mask(c, 0x2a, sixty?0x00:0x80, 0x80);
150 if (rc < 0)
151 goto out;
152
153 rc = ov_write(c, 0x2b, sixty?0x00:0xac);
154 if (rc < 0)
155 goto out;
156
157 rc = ov_write_mask(c, 0x76, 0x01, 0x01);
158 break;
159 }
160 case OVCAMCHIP_CID_BANDFILT:
161 rc = ov_write_mask(c, 0x2d, v?0x04:0x00, 0x04);
162 s->bandfilt = v;
163 break;
164 case OVCAMCHIP_CID_AUTOBRIGHT:
165 rc = ov_write_mask(c, 0x2d, v?0x10:0x00, 0x10);
166 s->auto_brt = v;
167 break;
168 case OVCAMCHIP_CID_AUTOEXP:
169 rc = ov_write_mask(c, 0x13, v?0x01:0x00, 0x01);
170 s->auto_exp = v;
171 break;
172 case OVCAMCHIP_CID_MIRROR:
173 rc = ov_write_mask(c, 0x12, v?0x40:0x00, 0x40);
174 s->mirror = v;
175 break;
176 default:
177 DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
178 return -EPERM;
179 }
180
181out:
182 DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, v, rc);
183 return rc;
184}
185
186static int ov76be_get_control(struct i2c_client *c,
187 struct ovcamchip_control *ctl)
188{
189 struct ovcamchip *ov = i2c_get_clientdata(c);
190 struct ov76be *s = ov->spriv;
191 int rc = 0;
192 unsigned char val = 0;
193
194 switch (ctl->id) {
195 case OVCAMCHIP_CID_BRIGHT:
196 rc = ov_read(c, REG_BRT, &val);
197 ctl->value = val << 8;
198 break;
199 case OVCAMCHIP_CID_SAT:
200 rc = ov_read(c, REG_SAT, &val);
201 ctl->value = val << 8;
202 break;
203 case OVCAMCHIP_CID_EXP:
204 rc = ov_read(c, REG_EXP, &val);
205 ctl->value = val;
206 break;
207 case OVCAMCHIP_CID_BANDFILT:
208 ctl->value = s->bandfilt;
209 break;
210 case OVCAMCHIP_CID_AUTOBRIGHT:
211 ctl->value = s->auto_brt;
212 break;
213 case OVCAMCHIP_CID_AUTOEXP:
214 ctl->value = s->auto_exp;
215 break;
216 case OVCAMCHIP_CID_MIRROR:
217 ctl->value = s->mirror;
218 break;
219 default:
220 DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
221 return -EPERM;
222 }
223
224 DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, ctl->value, rc);
225 return rc;
226}
227
228static int ov76be_mode_init(struct i2c_client *c, struct ovcamchip_window *win)
229{
230 int qvga = win->quarter;
231
232 /******** QVGA-specific regs ********/
233
234 ov_write(c, 0x14, qvga?0xa4:0x84);
235
236 /******** Palette-specific regs ********/
237
238 if (win->format == VIDEO_PALETTE_GREY) {
239 ov_write_mask(c, 0x0e, 0x40, 0x40);
240 ov_write_mask(c, 0x13, 0x20, 0x20);
241 } else {
242 ov_write_mask(c, 0x0e, 0x00, 0x40);
243 ov_write_mask(c, 0x13, 0x00, 0x20);
244 }
245
246 /******** Clock programming ********/
247
248 ov_write(c, 0x11, win->clockdiv);
249
250 /******** Resolution-specific ********/
251
252 if (win->width == 640 && win->height == 480)
253 ov_write(c, 0x35, 0x9e);
254 else
255 ov_write(c, 0x35, 0x1e);
256
257 return 0;
258}
259
260static int ov76be_set_window(struct i2c_client *c, struct ovcamchip_window *win)
261{
262 int ret, hwscale, vwscale;
263
264 ret = ov76be_mode_init(c, win);
265 if (ret < 0)
266 return ret;
267
268 if (win->quarter) {
269 hwscale = 1;
270 vwscale = 0;
271 } else {
272 hwscale = 2;
273 vwscale = 1;
274 }
275
276 ov_write(c, 0x17, HWSBASE + (win->x >> hwscale));
277 ov_write(c, 0x18, HWEBASE + ((win->x + win->width) >> hwscale));
278 ov_write(c, 0x19, VWSBASE + (win->y >> vwscale));
279 ov_write(c, 0x1a, VWEBASE + ((win->y + win->height) >> vwscale));
280
281 return 0;
282}
283
284static int ov76be_command(struct i2c_client *c, unsigned int cmd, void *arg)
285{
286 switch (cmd) {
287 case OVCAMCHIP_CMD_S_CTRL:
288 return ov76be_set_control(c, arg);
289 case OVCAMCHIP_CMD_G_CTRL:
290 return ov76be_get_control(c, arg);
291 case OVCAMCHIP_CMD_S_MODE:
292 return ov76be_set_window(c, arg);
293 default:
294 DDEBUG(2, &c->dev, "command not supported: %d", cmd);
295 return -ENOIOCTLCMD;
296 }
297}
298
299struct ovcamchip_ops ov76be_ops = {
300 .init = ov76be_init,
301 .free = ov76be_free,
302 .command = ov76be_command,
303};
diff --git a/drivers/media/video/ovcamchip/ov7x10.c b/drivers/media/video/ovcamchip/ov7x10.c
new file mode 100644
index 000000000000..6c383d4b14fa
--- /dev/null
+++ b/drivers/media/video/ovcamchip/ov7x10.c
@@ -0,0 +1,335 @@
1/* OmniVision OV7610/OV7110 Camera Chip Support Code
2 *
3 * Copyright (c) 1999-2004 Mark McClelland <mark@alpha.dyndns.org>
4 * http://alpha.dyndns.org/ov511/
5 *
6 * Color fixes by by Orion Sky Lawlor <olawlor@acm.org> (2/26/2000)
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version. NO WARRANTY OF ANY KIND is expressed or implied.
12 */
13
14#define DEBUG
15
16#include <linux/slab.h>
17#include "ovcamchip_priv.h"
18
19/* Registers */
20#define REG_GAIN 0x00 /* gain [5:0] */
21#define REG_BLUE 0x01 /* blue channel balance */
22#define REG_RED 0x02 /* red channel balance */
23#define REG_SAT 0x03 /* saturation */
24#define REG_CNT 0x05 /* Y contrast */
25#define REG_BRT 0x06 /* Y brightness */
26#define REG_BLUE_BIAS 0x0C /* blue channel bias [5:0] */
27#define REG_RED_BIAS 0x0D /* red channel bias [5:0] */
28#define REG_GAMMA_COEFF 0x0E /* gamma settings */
29#define REG_WB_RANGE 0x0F /* AEC/ALC/S-AWB settings */
30#define REG_EXP 0x10 /* manual exposure setting */
31#define REG_CLOCK 0x11 /* polarity/clock prescaler */
32#define REG_FIELD_DIVIDE 0x16 /* field interval/mode settings */
33#define REG_HWIN_START 0x17 /* horizontal window start */
34#define REG_HWIN_END 0x18 /* horizontal window end */
35#define REG_VWIN_START 0x19 /* vertical window start */
36#define REG_VWIN_END 0x1A /* vertical window end */
37#define REG_PIXEL_SHIFT 0x1B /* pixel shift */
38#define REG_YOFFSET 0x21 /* Y channel offset */
39#define REG_UOFFSET 0x22 /* U channel offset */
40#define REG_ECW 0x24 /* exposure white level for AEC */
41#define REG_ECB 0x25 /* exposure black level for AEC */
42#define REG_FRAMERATE_H 0x2A /* frame rate MSB + misc */
43#define REG_FRAMERATE_L 0x2B /* frame rate LSB */
44#define REG_ALC 0x2C /* Auto Level Control settings */
45#define REG_VOFFSET 0x2E /* V channel offset adjustment */
46#define REG_ARRAY_BIAS 0x2F /* array bias -- don't change */
47#define REG_YGAMMA 0x33 /* misc gamma settings [7:6] */
48#define REG_BIAS_ADJUST 0x34 /* misc bias settings */
49
50/* Window parameters */
51#define HWSBASE 0x38
52#define HWEBASE 0x3a
53#define VWSBASE 0x05
54#define VWEBASE 0x05
55
56struct ov7x10 {
57 int auto_brt;
58 int auto_exp;
59 int bandfilt;
60 int mirror;
61};
62
63/* Lawrence Glaister <lg@jfm.bc.ca> reports:
64 *
65 * Register 0x0f in the 7610 has the following effects:
66 *
67 * 0x85 (AEC method 1): Best overall, good contrast range
68 * 0x45 (AEC method 2): Very overexposed
69 * 0xa5 (spec sheet default): Ok, but the black level is
70 * shifted resulting in loss of contrast
71 * 0x05 (old driver setting): very overexposed, too much
72 * contrast
73 */
74static struct ovcamchip_regvals regvals_init_7x10[] = {
75 { 0x10, 0xff },
76 { 0x16, 0x03 },
77 { 0x28, 0x24 },
78 { 0x2b, 0xac },
79 { 0x12, 0x00 },
80 { 0x38, 0x81 },
81 { 0x28, 0x24 }, /* 0c */
82 { 0x0f, 0x85 }, /* lg's setting */
83 { 0x15, 0x01 },
84 { 0x20, 0x1c },
85 { 0x23, 0x2a },
86 { 0x24, 0x10 },
87 { 0x25, 0x8a },
88 { 0x26, 0xa2 },
89 { 0x27, 0xc2 },
90 { 0x2a, 0x04 },
91 { 0x2c, 0xfe },
92 { 0x2d, 0x93 },
93 { 0x30, 0x71 },
94 { 0x31, 0x60 },
95 { 0x32, 0x26 },
96 { 0x33, 0x20 },
97 { 0x34, 0x48 },
98 { 0x12, 0x24 },
99 { 0x11, 0x01 },
100 { 0x0c, 0x24 },
101 { 0x0d, 0x24 },
102 { 0xff, 0xff }, /* END MARKER */
103};
104
105/* This initializes the OV7x10 camera chip and relevant variables. */
106static int ov7x10_init(struct i2c_client *c)
107{
108 struct ovcamchip *ov = i2c_get_clientdata(c);
109 struct ov7x10 *s;
110 int rc;
111
112 DDEBUG(4, &c->dev, "entered");
113
114 rc = ov_write_regvals(c, regvals_init_7x10);
115 if (rc < 0)
116 return rc;
117
118 ov->spriv = s = kmalloc(sizeof *s, GFP_KERNEL);
119 if (!s)
120 return -ENOMEM;
121 memset(s, 0, sizeof *s);
122
123 s->auto_brt = 1;
124 s->auto_exp = 1;
125
126 return rc;
127}
128
129static int ov7x10_free(struct i2c_client *c)
130{
131 struct ovcamchip *ov = i2c_get_clientdata(c);
132
133 kfree(ov->spriv);
134 return 0;
135}
136
137static int ov7x10_set_control(struct i2c_client *c,
138 struct ovcamchip_control *ctl)
139{
140 struct ovcamchip *ov = i2c_get_clientdata(c);
141 struct ov7x10 *s = ov->spriv;
142 int rc;
143 int v = ctl->value;
144
145 switch (ctl->id) {
146 case OVCAMCHIP_CID_CONT:
147 rc = ov_write(c, REG_CNT, v >> 8);
148 break;
149 case OVCAMCHIP_CID_BRIGHT:
150 rc = ov_write(c, REG_BRT, v >> 8);
151 break;
152 case OVCAMCHIP_CID_SAT:
153 rc = ov_write(c, REG_SAT, v >> 8);
154 break;
155 case OVCAMCHIP_CID_HUE:
156 rc = ov_write(c, REG_RED, 0xFF - (v >> 8));
157 if (rc < 0)
158 goto out;
159
160 rc = ov_write(c, REG_BLUE, v >> 8);
161 break;
162 case OVCAMCHIP_CID_EXP:
163 rc = ov_write(c, REG_EXP, v);
164 break;
165 case OVCAMCHIP_CID_FREQ:
166 {
167 int sixty = (v == 60);
168
169 rc = ov_write_mask(c, 0x2a, sixty?0x00:0x80, 0x80);
170 if (rc < 0)
171 goto out;
172
173 rc = ov_write(c, 0x2b, sixty?0x00:0xac);
174 if (rc < 0)
175 goto out;
176
177 rc = ov_write_mask(c, 0x13, 0x10, 0x10);
178 if (rc < 0)
179 goto out;
180
181 rc = ov_write_mask(c, 0x13, 0x00, 0x10);
182 break;
183 }
184 case OVCAMCHIP_CID_BANDFILT:
185 rc = ov_write_mask(c, 0x2d, v?0x04:0x00, 0x04);
186 s->bandfilt = v;
187 break;
188 case OVCAMCHIP_CID_AUTOBRIGHT:
189 rc = ov_write_mask(c, 0x2d, v?0x10:0x00, 0x10);
190 s->auto_brt = v;
191 break;
192 case OVCAMCHIP_CID_AUTOEXP:
193 rc = ov_write_mask(c, 0x29, v?0x00:0x80, 0x80);
194 s->auto_exp = v;
195 break;
196 case OVCAMCHIP_CID_MIRROR:
197 rc = ov_write_mask(c, 0x12, v?0x40:0x00, 0x40);
198 s->mirror = v;
199 break;
200 default:
201 DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
202 return -EPERM;
203 }
204
205out:
206 DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, v, rc);
207 return rc;
208}
209
210static int ov7x10_get_control(struct i2c_client *c,
211 struct ovcamchip_control *ctl)
212{
213 struct ovcamchip *ov = i2c_get_clientdata(c);
214 struct ov7x10 *s = ov->spriv;
215 int rc = 0;
216 unsigned char val = 0;
217
218 switch (ctl->id) {
219 case OVCAMCHIP_CID_CONT:
220 rc = ov_read(c, REG_CNT, &val);
221 ctl->value = val << 8;
222 break;
223 case OVCAMCHIP_CID_BRIGHT:
224 rc = ov_read(c, REG_BRT, &val);
225 ctl->value = val << 8;
226 break;
227 case OVCAMCHIP_CID_SAT:
228 rc = ov_read(c, REG_SAT, &val);
229 ctl->value = val << 8;
230 break;
231 case OVCAMCHIP_CID_HUE:
232 rc = ov_read(c, REG_BLUE, &val);
233 ctl->value = val << 8;
234 break;
235 case OVCAMCHIP_CID_EXP:
236 rc = ov_read(c, REG_EXP, &val);
237 ctl->value = val;
238 break;
239 case OVCAMCHIP_CID_BANDFILT:
240 ctl->value = s->bandfilt;
241 break;
242 case OVCAMCHIP_CID_AUTOBRIGHT:
243 ctl->value = s->auto_brt;
244 break;
245 case OVCAMCHIP_CID_AUTOEXP:
246 ctl->value = s->auto_exp;
247 break;
248 case OVCAMCHIP_CID_MIRROR:
249 ctl->value = s->mirror;
250 break;
251 default:
252 DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
253 return -EPERM;
254 }
255
256 DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, ctl->value, rc);
257 return rc;
258}
259
260static int ov7x10_mode_init(struct i2c_client *c, struct ovcamchip_window *win)
261{
262 int qvga = win->quarter;
263
264 /******** QVGA-specific regs ********/
265
266 ov_write(c, 0x14, qvga?0x24:0x04);
267
268 /******** Palette-specific regs ********/
269
270 if (win->format == VIDEO_PALETTE_GREY) {
271 ov_write_mask(c, 0x0e, 0x40, 0x40);
272 ov_write_mask(c, 0x13, 0x20, 0x20);
273 } else {
274 ov_write_mask(c, 0x0e, 0x00, 0x40);
275 ov_write_mask(c, 0x13, 0x00, 0x20);
276 }
277
278 /******** Clock programming ********/
279
280 ov_write(c, 0x11, win->clockdiv);
281
282 /******** Resolution-specific ********/
283
284 if (win->width == 640 && win->height == 480)
285 ov_write(c, 0x35, 0x9e);
286 else
287 ov_write(c, 0x35, 0x1e);
288
289 return 0;
290}
291
292static int ov7x10_set_window(struct i2c_client *c, struct ovcamchip_window *win)
293{
294 int ret, hwscale, vwscale;
295
296 ret = ov7x10_mode_init(c, win);
297 if (ret < 0)
298 return ret;
299
300 if (win->quarter) {
301 hwscale = 1;
302 vwscale = 0;
303 } else {
304 hwscale = 2;
305 vwscale = 1;
306 }
307
308 ov_write(c, 0x17, HWSBASE + (win->x >> hwscale));
309 ov_write(c, 0x18, HWEBASE + ((win->x + win->width) >> hwscale));
310 ov_write(c, 0x19, VWSBASE + (win->y >> vwscale));
311 ov_write(c, 0x1a, VWEBASE + ((win->y + win->height) >> vwscale));
312
313 return 0;
314}
315
316static int ov7x10_command(struct i2c_client *c, unsigned int cmd, void *arg)
317{
318 switch (cmd) {
319 case OVCAMCHIP_CMD_S_CTRL:
320 return ov7x10_set_control(c, arg);
321 case OVCAMCHIP_CMD_G_CTRL:
322 return ov7x10_get_control(c, arg);
323 case OVCAMCHIP_CMD_S_MODE:
324 return ov7x10_set_window(c, arg);
325 default:
326 DDEBUG(2, &c->dev, "command not supported: %d", cmd);
327 return -ENOIOCTLCMD;
328 }
329}
330
331struct ovcamchip_ops ov7x10_ops = {
332 .init = ov7x10_init,
333 .free = ov7x10_free,
334 .command = ov7x10_command,
335};
diff --git a/drivers/media/video/ovcamchip/ov7x20.c b/drivers/media/video/ovcamchip/ov7x20.c
new file mode 100644
index 000000000000..3c8c48f338ba
--- /dev/null
+++ b/drivers/media/video/ovcamchip/ov7x20.c
@@ -0,0 +1,455 @@
1/* OmniVision OV7620/OV7120 Camera Chip Support Code
2 *
3 * Copyright (c) 1999-2004 Mark McClelland <mark@alpha.dyndns.org>
4 * http://alpha.dyndns.org/ov511/
5 *
6 * OV7620 fixes by Charl P. Botha <cpbotha@ieee.org>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version. NO WARRANTY OF ANY KIND is expressed or implied.
12 */
13
14#define DEBUG
15
16#include <linux/slab.h>
17#include "ovcamchip_priv.h"
18
19/* Registers */
20#define REG_GAIN 0x00 /* gain [5:0] */
21#define REG_BLUE 0x01 /* blue gain */
22#define REG_RED 0x02 /* red gain */
23#define REG_SAT 0x03 /* saturation */
24#define REG_BRT 0x06 /* Y brightness */
25#define REG_SHARP 0x07 /* analog sharpness */
26#define REG_BLUE_BIAS 0x0C /* WB blue ratio [5:0] */
27#define REG_RED_BIAS 0x0D /* WB red ratio [5:0] */
28#define REG_EXP 0x10 /* exposure */
29
30/* Default control settings. Values are in terms of V4L2 controls. */
31#define OV7120_DFL_BRIGHT 0x60
32#define OV7620_DFL_BRIGHT 0x60
33#define OV7120_DFL_SAT 0xb0
34#define OV7620_DFL_SAT 0xc0
35#define DFL_AUTO_EXP 1
36#define DFL_AUTO_GAIN 1
37#define OV7120_DFL_GAIN 0x00
38#define OV7620_DFL_GAIN 0x00
39/* NOTE: Since autoexposure is the default, these aren't programmed into the
40 * OV7x20 chip. They are just here because V4L2 expects a default */
41#define OV7120_DFL_EXP 0x7f
42#define OV7620_DFL_EXP 0x7f
43
44/* Window parameters */
45#define HWSBASE 0x2F /* From 7620.SET (spec is wrong) */
46#define HWEBASE 0x2F
47#define VWSBASE 0x05
48#define VWEBASE 0x05
49
50struct ov7x20 {
51 int auto_brt;
52 int auto_exp;
53 int auto_gain;
54 int backlight;
55 int bandfilt;
56 int mirror;
57};
58
59/* Contrast look-up table */
60static unsigned char ctab[] = {
61 0x01, 0x05, 0x09, 0x11, 0x15, 0x35, 0x37, 0x57,
62 0x5b, 0xa5, 0xa7, 0xc7, 0xc9, 0xcf, 0xef, 0xff
63};
64
65/* Settings for (Black & White) OV7120 camera chip */
66static struct ovcamchip_regvals regvals_init_7120[] = {
67 { 0x12, 0x80 }, /* reset */
68 { 0x13, 0x00 }, /* Autoadjust off */
69 { 0x12, 0x20 }, /* Disable AWB */
70 { 0x13, DFL_AUTO_GAIN?0x01:0x00 }, /* Autoadjust on (if desired) */
71 { 0x00, OV7120_DFL_GAIN },
72 { 0x01, 0x80 },
73 { 0x02, 0x80 },
74 { 0x03, OV7120_DFL_SAT },
75 { 0x06, OV7120_DFL_BRIGHT },
76 { 0x07, 0x00 },
77 { 0x0c, 0x20 },
78 { 0x0d, 0x20 },
79 { 0x11, 0x01 },
80 { 0x14, 0x84 },
81 { 0x15, 0x01 },
82 { 0x16, 0x03 },
83 { 0x17, 0x2f },
84 { 0x18, 0xcf },
85 { 0x19, 0x06 },
86 { 0x1a, 0xf5 },
87 { 0x1b, 0x00 },
88 { 0x20, 0x08 },
89 { 0x21, 0x80 },
90 { 0x22, 0x80 },
91 { 0x23, 0x00 },
92 { 0x26, 0xa0 },
93 { 0x27, 0xfa },
94 { 0x28, 0x20 }, /* DON'T set bit 6. It is for the OV7620 only */
95 { 0x29, DFL_AUTO_EXP?0x00:0x80 },
96 { 0x2a, 0x10 },
97 { 0x2b, 0x00 },
98 { 0x2c, 0x88 },
99 { 0x2d, 0x95 },
100 { 0x2e, 0x80 },
101 { 0x2f, 0x44 },
102 { 0x60, 0x20 },
103 { 0x61, 0x02 },
104 { 0x62, 0x5f },
105 { 0x63, 0xd5 },
106 { 0x64, 0x57 },
107 { 0x65, 0x83 }, /* OV says "don't change this value" */
108 { 0x66, 0x55 },
109 { 0x67, 0x92 },
110 { 0x68, 0xcf },
111 { 0x69, 0x76 },
112 { 0x6a, 0x22 },
113 { 0x6b, 0xe2 },
114 { 0x6c, 0x40 },
115 { 0x6d, 0x48 },
116 { 0x6e, 0x80 },
117 { 0x6f, 0x0d },
118 { 0x70, 0x89 },
119 { 0x71, 0x00 },
120 { 0x72, 0x14 },
121 { 0x73, 0x54 },
122 { 0x74, 0xa0 },
123 { 0x75, 0x8e },
124 { 0x76, 0x00 },
125 { 0x77, 0xff },
126 { 0x78, 0x80 },
127 { 0x79, 0x80 },
128 { 0x7a, 0x80 },
129 { 0x7b, 0xe6 },
130 { 0x7c, 0x00 },
131 { 0x24, 0x3a },
132 { 0x25, 0x60 },
133 { 0xff, 0xff }, /* END MARKER */
134};
135
136/* Settings for (color) OV7620 camera chip */
137static struct ovcamchip_regvals regvals_init_7620[] = {
138 { 0x12, 0x80 }, /* reset */
139 { 0x00, OV7620_DFL_GAIN },
140 { 0x01, 0x80 },
141 { 0x02, 0x80 },
142 { 0x03, OV7620_DFL_SAT },
143 { 0x06, OV7620_DFL_BRIGHT },
144 { 0x07, 0x00 },
145 { 0x0c, 0x24 },
146 { 0x0c, 0x24 },
147 { 0x0d, 0x24 },
148 { 0x11, 0x01 },
149 { 0x12, 0x24 },
150 { 0x13, DFL_AUTO_GAIN?0x01:0x00 },
151 { 0x14, 0x84 },
152 { 0x15, 0x01 },
153 { 0x16, 0x03 },
154 { 0x17, 0x2f },
155 { 0x18, 0xcf },
156 { 0x19, 0x06 },
157 { 0x1a, 0xf5 },
158 { 0x1b, 0x00 },
159 { 0x20, 0x18 },
160 { 0x21, 0x80 },
161 { 0x22, 0x80 },
162 { 0x23, 0x00 },
163 { 0x26, 0xa2 },
164 { 0x27, 0xea },
165 { 0x28, 0x20 },
166 { 0x29, DFL_AUTO_EXP?0x00:0x80 },
167 { 0x2a, 0x10 },
168 { 0x2b, 0x00 },
169 { 0x2c, 0x88 },
170 { 0x2d, 0x91 },
171 { 0x2e, 0x80 },
172 { 0x2f, 0x44 },
173 { 0x60, 0x27 },
174 { 0x61, 0x02 },
175 { 0x62, 0x5f },
176 { 0x63, 0xd5 },
177 { 0x64, 0x57 },
178 { 0x65, 0x83 },
179 { 0x66, 0x55 },
180 { 0x67, 0x92 },
181 { 0x68, 0xcf },
182 { 0x69, 0x76 },
183 { 0x6a, 0x22 },
184 { 0x6b, 0x00 },
185 { 0x6c, 0x02 },
186 { 0x6d, 0x44 },
187 { 0x6e, 0x80 },
188 { 0x6f, 0x1d },
189 { 0x70, 0x8b },
190 { 0x71, 0x00 },
191 { 0x72, 0x14 },
192 { 0x73, 0x54 },
193 { 0x74, 0x00 },
194 { 0x75, 0x8e },
195 { 0x76, 0x00 },
196 { 0x77, 0xff },
197 { 0x78, 0x80 },
198 { 0x79, 0x80 },
199 { 0x7a, 0x80 },
200 { 0x7b, 0xe2 },
201 { 0x7c, 0x00 },
202 { 0xff, 0xff }, /* END MARKER */
203};
204
205/* Returns index into the specified look-up table, with 'n' elements, for which
206 * the value is greater than or equal to "val". If a match isn't found, (n-1)
207 * is returned. The entries in the table must be in ascending order. */
208static inline int ov7x20_lut_find(unsigned char lut[], int n, unsigned char val)
209{
210 int i = 0;
211
212 while (lut[i] < val && i < n)
213 i++;
214
215 return i;
216}
217
218/* This initializes the OV7x20 camera chip and relevant variables. */
219static int ov7x20_init(struct i2c_client *c)
220{
221 struct ovcamchip *ov = i2c_get_clientdata(c);
222 struct ov7x20 *s;
223 int rc;
224
225 DDEBUG(4, &c->dev, "entered");
226
227 if (ov->mono)
228 rc = ov_write_regvals(c, regvals_init_7120);
229 else
230 rc = ov_write_regvals(c, regvals_init_7620);
231
232 if (rc < 0)
233 return rc;
234
235 ov->spriv = s = kmalloc(sizeof *s, GFP_KERNEL);
236 if (!s)
237 return -ENOMEM;
238 memset(s, 0, sizeof *s);
239
240 s->auto_brt = 1;
241 s->auto_exp = DFL_AUTO_EXP;
242 s->auto_gain = DFL_AUTO_GAIN;
243
244 return 0;
245}
246
247static int ov7x20_free(struct i2c_client *c)
248{
249 struct ovcamchip *ov = i2c_get_clientdata(c);
250
251 kfree(ov->spriv);
252 return 0;
253}
254
255static int ov7x20_set_v4l1_control(struct i2c_client *c,
256 struct ovcamchip_control *ctl)
257{
258 struct ovcamchip *ov = i2c_get_clientdata(c);
259 struct ov7x20 *s = ov->spriv;
260 int rc;
261 int v = ctl->value;
262
263 switch (ctl->id) {
264 case OVCAMCHIP_CID_CONT:
265 {
266 /* Use Y gamma control instead. Bit 0 enables it. */
267 rc = ov_write(c, 0x64, ctab[v >> 12]);
268 break;
269 }
270 case OVCAMCHIP_CID_BRIGHT:
271 /* 7620 doesn't like manual changes when in auto mode */
272 if (!s->auto_brt)
273 rc = ov_write(c, REG_BRT, v >> 8);
274 else
275 rc = 0;
276 break;
277 case OVCAMCHIP_CID_SAT:
278 rc = ov_write(c, REG_SAT, v >> 8);
279 break;
280 case OVCAMCHIP_CID_EXP:
281 if (!s->auto_exp)
282 rc = ov_write(c, REG_EXP, v);
283 else
284 rc = -EBUSY;
285 break;
286 case OVCAMCHIP_CID_FREQ:
287 {
288 int sixty = (v == 60);
289
290 rc = ov_write_mask(c, 0x2a, sixty?0x00:0x80, 0x80);
291 if (rc < 0)
292 goto out;
293
294 rc = ov_write(c, 0x2b, sixty?0x00:0xac);
295 if (rc < 0)
296 goto out;
297
298 rc = ov_write_mask(c, 0x76, 0x01, 0x01);
299 break;
300 }
301 case OVCAMCHIP_CID_BANDFILT:
302 rc = ov_write_mask(c, 0x2d, v?0x04:0x00, 0x04);
303 s->bandfilt = v;
304 break;
305 case OVCAMCHIP_CID_AUTOBRIGHT:
306 rc = ov_write_mask(c, 0x2d, v?0x10:0x00, 0x10);
307 s->auto_brt = v;
308 break;
309 case OVCAMCHIP_CID_AUTOEXP:
310 rc = ov_write_mask(c, 0x13, v?0x01:0x00, 0x01);
311 s->auto_exp = v;
312 break;
313 case OVCAMCHIP_CID_BACKLIGHT:
314 {
315 rc = ov_write_mask(c, 0x68, v?0xe0:0xc0, 0xe0);
316 if (rc < 0)
317 goto out;
318
319 rc = ov_write_mask(c, 0x29, v?0x08:0x00, 0x08);
320 if (rc < 0)
321 goto out;
322
323 rc = ov_write_mask(c, 0x28, v?0x02:0x00, 0x02);
324 s->backlight = v;
325 break;
326 }
327 case OVCAMCHIP_CID_MIRROR:
328 rc = ov_write_mask(c, 0x12, v?0x40:0x00, 0x40);
329 s->mirror = v;
330 break;
331 default:
332 DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
333 return -EPERM;
334 }
335
336out:
337 DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, v, rc);
338 return rc;
339}
340
341static int ov7x20_get_v4l1_control(struct i2c_client *c,
342 struct ovcamchip_control *ctl)
343{
344 struct ovcamchip *ov = i2c_get_clientdata(c);
345 struct ov7x20 *s = ov->spriv;
346 int rc = 0;
347 unsigned char val = 0;
348
349 switch (ctl->id) {
350 case OVCAMCHIP_CID_CONT:
351 rc = ov_read(c, 0x64, &val);
352 ctl->value = ov7x20_lut_find(ctab, 16, val) << 12;
353 break;
354 case OVCAMCHIP_CID_BRIGHT:
355 rc = ov_read(c, REG_BRT, &val);
356 ctl->value = val << 8;
357 break;
358 case OVCAMCHIP_CID_SAT:
359 rc = ov_read(c, REG_SAT, &val);
360 ctl->value = val << 8;
361 break;
362 case OVCAMCHIP_CID_EXP:
363 rc = ov_read(c, REG_EXP, &val);
364 ctl->value = val;
365 break;
366 case OVCAMCHIP_CID_BANDFILT:
367 ctl->value = s->bandfilt;
368 break;
369 case OVCAMCHIP_CID_AUTOBRIGHT:
370 ctl->value = s->auto_brt;
371 break;
372 case OVCAMCHIP_CID_AUTOEXP:
373 ctl->value = s->auto_exp;
374 break;
375 case OVCAMCHIP_CID_BACKLIGHT:
376 ctl->value = s->backlight;
377 break;
378 case OVCAMCHIP_CID_MIRROR:
379 ctl->value = s->mirror;
380 break;
381 default:
382 DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
383 return -EPERM;
384 }
385
386 DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, ctl->value, rc);
387 return rc;
388}
389
390static int ov7x20_mode_init(struct i2c_client *c, struct ovcamchip_window *win)
391{
392 struct ovcamchip *ov = i2c_get_clientdata(c);
393 int qvga = win->quarter;
394
395 /******** QVGA-specific regs ********/
396 ov_write_mask(c, 0x14, qvga?0x20:0x00, 0x20);
397 ov_write_mask(c, 0x28, qvga?0x00:0x20, 0x20);
398 ov_write(c, 0x24, qvga?0x20:0x3a);
399 ov_write(c, 0x25, qvga?0x30:0x60);
400 ov_write_mask(c, 0x2d, qvga?0x40:0x00, 0x40);
401 if (!ov->mono)
402 ov_write_mask(c, 0x67, qvga?0xf0:0x90, 0xf0);
403 ov_write_mask(c, 0x74, qvga?0x20:0x00, 0x20);
404
405 /******** Clock programming ********/
406
407 ov_write(c, 0x11, win->clockdiv);
408
409 return 0;
410}
411
412static int ov7x20_set_window(struct i2c_client *c, struct ovcamchip_window *win)
413{
414 int ret, hwscale, vwscale;
415
416 ret = ov7x20_mode_init(c, win);
417 if (ret < 0)
418 return ret;
419
420 if (win->quarter) {
421 hwscale = 1;
422 vwscale = 0;
423 } else {
424 hwscale = 2;
425 vwscale = 1;
426 }
427
428 ov_write(c, 0x17, HWSBASE + (win->x >> hwscale));
429 ov_write(c, 0x18, HWEBASE + ((win->x + win->width) >> hwscale));
430 ov_write(c, 0x19, VWSBASE + (win->y >> vwscale));
431 ov_write(c, 0x1a, VWEBASE + ((win->y + win->height) >> vwscale));
432
433 return 0;
434}
435
436static int ov7x20_command(struct i2c_client *c, unsigned int cmd, void *arg)
437{
438 switch (cmd) {
439 case OVCAMCHIP_CMD_S_CTRL:
440 return ov7x20_set_v4l1_control(c, arg);
441 case OVCAMCHIP_CMD_G_CTRL:
442 return ov7x20_get_v4l1_control(c, arg);
443 case OVCAMCHIP_CMD_S_MODE:
444 return ov7x20_set_window(c, arg);
445 default:
446 DDEBUG(2, &c->dev, "command not supported: %d", cmd);
447 return -ENOIOCTLCMD;
448 }
449}
450
451struct ovcamchip_ops ov7x20_ops = {
452 .init = ov7x20_init,
453 .free = ov7x20_free,
454 .command = ov7x20_command,
455};
diff --git a/drivers/media/video/ovcamchip/ovcamchip_core.c b/drivers/media/video/ovcamchip/ovcamchip_core.c
new file mode 100644
index 000000000000..54dd5612d3b8
--- /dev/null
+++ b/drivers/media/video/ovcamchip/ovcamchip_core.c
@@ -0,0 +1,444 @@
1/* Shared Code for OmniVision Camera Chip Drivers
2 *
3 * Copyright (c) 2004 Mark McClelland <mark@alpha.dyndns.org>
4 * http://alpha.dyndns.org/ov511/
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. NO WARRANTY OF ANY KIND is expressed or implied.
10 */
11
12#define DEBUG
13
14#include <linux/init.h>
15#include <linux/module.h>
16#include <linux/moduleparam.h>
17#include <linux/slab.h>
18#include <linux/delay.h>
19#include "ovcamchip_priv.h"
20
21#define DRIVER_VERSION "v2.27 for Linux 2.6"
22#define DRIVER_AUTHOR "Mark McClelland <mark@alpha.dyndns.org>"
23#define DRIVER_DESC "OV camera chip I2C driver"
24
25#define PINFO(fmt, args...) printk(KERN_INFO "ovcamchip: " fmt "\n" , ## args);
26#define PERROR(fmt, args...) printk(KERN_ERR "ovcamchip: " fmt "\n" , ## args);
27
28#ifdef DEBUG
29int ovcamchip_debug = 0;
30static int debug;
31module_param(debug, int, 0);
32MODULE_PARM_DESC(debug,
33 "Debug level: 0=none, 1=inits, 2=warning, 3=config, 4=functions, 5=all");
34#endif
35
36/* By default, let bridge driver tell us if chip is monochrome. mono=0
37 * will ignore that and always treat chips as color. mono=1 will force
38 * monochrome mode for all chips. */
39static int mono = -1;
40module_param(mono, int, 0);
41MODULE_PARM_DESC(mono,
42 "1=chips are monochrome (OVx1xx), 0=force color, -1=autodetect (default)");
43
44MODULE_AUTHOR(DRIVER_AUTHOR);
45MODULE_DESCRIPTION(DRIVER_DESC);
46MODULE_LICENSE("GPL");
47
48/* Registers common to all chips, that are needed for detection */
49#define GENERIC_REG_ID_HIGH 0x1C /* manufacturer ID MSB */
50#define GENERIC_REG_ID_LOW 0x1D /* manufacturer ID LSB */
51#define GENERIC_REG_COM_I 0x29 /* misc ID bits */
52
53extern struct ovcamchip_ops ov6x20_ops;
54extern struct ovcamchip_ops ov6x30_ops;
55extern struct ovcamchip_ops ov7x10_ops;
56extern struct ovcamchip_ops ov7x20_ops;
57extern struct ovcamchip_ops ov76be_ops;
58
59static char *chip_names[NUM_CC_TYPES] = {
60 [CC_UNKNOWN] = "Unknown chip",
61 [CC_OV76BE] = "OV76BE",
62 [CC_OV7610] = "OV7610",
63 [CC_OV7620] = "OV7620",
64 [CC_OV7620AE] = "OV7620AE",
65 [CC_OV6620] = "OV6620",
66 [CC_OV6630] = "OV6630",
67 [CC_OV6630AE] = "OV6630AE",
68 [CC_OV6630AF] = "OV6630AF",
69};
70
71/* Forward declarations */
72static struct i2c_driver driver;
73static struct i2c_client client_template;
74
75/* ----------------------------------------------------------------------- */
76
77int ov_write_regvals(struct i2c_client *c, struct ovcamchip_regvals *rvals)
78{
79 int rc;
80
81 while (rvals->reg != 0xff) {
82 rc = ov_write(c, rvals->reg, rvals->val);
83 if (rc < 0)
84 return rc;
85 rvals++;
86 }
87
88 return 0;
89}
90
91/* Writes bits at positions specified by mask to an I2C reg. Bits that are in
92 * the same position as 1's in "mask" are cleared and set to "value". Bits
93 * that are in the same position as 0's in "mask" are preserved, regardless
94 * of their respective state in "value".
95 */
96int ov_write_mask(struct i2c_client *c,
97 unsigned char reg,
98 unsigned char value,
99 unsigned char mask)
100{
101 int rc;
102 unsigned char oldval, newval;
103
104 if (mask == 0xff) {
105 newval = value;
106 } else {
107 rc = ov_read(c, reg, &oldval);
108 if (rc < 0)
109 return rc;
110
111 oldval &= (~mask); /* Clear the masked bits */
112 value &= mask; /* Enforce mask on value */
113 newval = oldval | value; /* Set the desired bits */
114 }
115
116 return ov_write(c, reg, newval);
117}
118
119/* ----------------------------------------------------------------------- */
120
121/* Reset the chip and ensure that I2C is synchronized. Returns <0 if failure.
122 */
123static int init_camchip(struct i2c_client *c)
124{
125 int i, success;
126 unsigned char high, low;
127
128 /* Reset the chip */
129 ov_write(c, 0x12, 0x80);
130
131 /* Wait for it to initialize */
132 msleep(150);
133
134 for (i = 0, success = 0; i < I2C_DETECT_RETRIES && !success; i++) {
135 if (ov_read(c, GENERIC_REG_ID_HIGH, &high) >= 0) {
136 if (ov_read(c, GENERIC_REG_ID_LOW, &low) >= 0) {
137 if (high == 0x7F && low == 0xA2) {
138 success = 1;
139 continue;
140 }
141 }
142 }
143
144 /* Reset the chip */
145 ov_write(c, 0x12, 0x80);
146
147 /* Wait for it to initialize */
148 msleep(150);
149
150 /* Dummy read to sync I2C */
151 ov_read(c, 0x00, &low);
152 }
153
154 if (!success)
155 return -EIO;
156
157 PDEBUG(1, "I2C synced in %d attempt(s)", i);
158
159 return 0;
160}
161
162/* This detects the OV7610, OV7620, or OV76BE chip. */
163static int ov7xx0_detect(struct i2c_client *c)
164{
165 struct ovcamchip *ov = i2c_get_clientdata(c);
166 int rc;
167 unsigned char val;
168
169 PDEBUG(4, "");
170
171 /* Detect chip (sub)type */
172 rc = ov_read(c, GENERIC_REG_COM_I, &val);
173 if (rc < 0) {
174 PERROR("Error detecting ov7xx0 type");
175 return rc;
176 }
177
178 if ((val & 3) == 3) {
179 PINFO("Camera chip is an OV7610");
180 ov->subtype = CC_OV7610;
181 } else if ((val & 3) == 1) {
182 rc = ov_read(c, 0x15, &val);
183 if (rc < 0) {
184 PERROR("Error detecting ov7xx0 type");
185 return rc;
186 }
187
188 if (val & 1) {
189 PINFO("Camera chip is an OV7620AE");
190 /* OV7620 is a close enough match for now. There are
191 * some definite differences though, so this should be
192 * fixed */
193 ov->subtype = CC_OV7620;
194 } else {
195 PINFO("Camera chip is an OV76BE");
196 ov->subtype = CC_OV76BE;
197 }
198 } else if ((val & 3) == 0) {
199 PINFO("Camera chip is an OV7620");
200 ov->subtype = CC_OV7620;
201 } else {
202 PERROR("Unknown camera chip version: %d", val & 3);
203 return -ENOSYS;
204 }
205
206 if (ov->subtype == CC_OV76BE)
207 ov->sops = &ov76be_ops;
208 else if (ov->subtype == CC_OV7620)
209 ov->sops = &ov7x20_ops;
210 else
211 ov->sops = &ov7x10_ops;
212
213 return 0;
214}
215
216/* This detects the OV6620, OV6630, OV6630AE, or OV6630AF chip. */
217static int ov6xx0_detect(struct i2c_client *c)
218{
219 struct ovcamchip *ov = i2c_get_clientdata(c);
220 int rc;
221 unsigned char val;
222
223 PDEBUG(4, "");
224
225 /* Detect chip (sub)type */
226 rc = ov_read(c, GENERIC_REG_COM_I, &val);
227 if (rc < 0) {
228 PERROR("Error detecting ov6xx0 type");
229 return -1;
230 }
231
232 if ((val & 3) == 0) {
233 ov->subtype = CC_OV6630;
234 PINFO("Camera chip is an OV6630");
235 } else if ((val & 3) == 1) {
236 ov->subtype = CC_OV6620;
237 PINFO("Camera chip is an OV6620");
238 } else if ((val & 3) == 2) {
239 ov->subtype = CC_OV6630;
240 PINFO("Camera chip is an OV6630AE");
241 } else if ((val & 3) == 3) {
242 ov->subtype = CC_OV6630;
243 PINFO("Camera chip is an OV6630AF");
244 }
245
246 if (ov->subtype == CC_OV6620)
247 ov->sops = &ov6x20_ops;
248 else
249 ov->sops = &ov6x30_ops;
250
251 return 0;
252}
253
254static int ovcamchip_detect(struct i2c_client *c)
255{
256 /* Ideally we would just try a single register write and see if it NAKs.
257 * That isn't possible since the OV518 can't report I2C transaction
258 * failures. So, we have to try to initialize the chip (i.e. reset it
259 * and check the ID registers) to detect its presence. */
260
261 /* Test for 7xx0 */
262 PDEBUG(3, "Testing for 0V7xx0");
263 c->addr = OV7xx0_SID;
264 if (init_camchip(c) < 0) {
265 /* Test for 6xx0 */
266 PDEBUG(3, "Testing for 0V6xx0");
267 c->addr = OV6xx0_SID;
268 if (init_camchip(c) < 0) {
269 return -ENODEV;
270 } else {
271 if (ov6xx0_detect(c) < 0) {
272 PERROR("Failed to init OV6xx0");
273 return -EIO;
274 }
275 }
276 } else {
277 if (ov7xx0_detect(c) < 0) {
278 PERROR("Failed to init OV7xx0");
279 return -EIO;
280 }
281 }
282
283 return 0;
284}
285
286/* ----------------------------------------------------------------------- */
287
288static int ovcamchip_attach(struct i2c_adapter *adap)
289{
290 int rc = 0;
291 struct ovcamchip *ov;
292 struct i2c_client *c;
293
294 /* I2C is not a PnP bus, so we can never be certain that we're talking
295 * to the right chip. To prevent damage to EEPROMS and such, only
296 * attach to adapters that are known to contain OV camera chips. */
297
298 switch (adap->id) {
299 case (I2C_ALGO_SMBUS | I2C_HW_SMBUS_OV511):
300 case (I2C_ALGO_SMBUS | I2C_HW_SMBUS_OV518):
301 case (I2C_ALGO_SMBUS | I2C_HW_SMBUS_OVFX2):
302 case (I2C_ALGO_SMBUS | I2C_HW_SMBUS_W9968CF):
303 PDEBUG(1, "Adapter ID 0x%06x accepted", adap->id);
304 break;
305 default:
306 PDEBUG(1, "Adapter ID 0x%06x rejected", adap->id);
307 return -ENODEV;
308 }
309
310 c = kmalloc(sizeof *c, GFP_KERNEL);
311 if (!c) {
312 rc = -ENOMEM;
313 goto no_client;
314 }
315 memcpy(c, &client_template, sizeof *c);
316 c->adapter = adap;
317 strcpy(i2c_clientname(c), "OV????");
318
319 ov = kmalloc(sizeof *ov, GFP_KERNEL);
320 if (!ov) {
321 rc = -ENOMEM;
322 goto no_ov;
323 }
324 memset(ov, 0, sizeof *ov);
325 i2c_set_clientdata(c, ov);
326
327 rc = ovcamchip_detect(c);
328 if (rc < 0)
329 goto error;
330
331 strcpy(i2c_clientname(c), chip_names[ov->subtype]);
332
333 PDEBUG(1, "Camera chip detection complete");
334
335 i2c_attach_client(c);
336
337 return rc;
338error:
339 kfree(ov);
340no_ov:
341 kfree(c);
342no_client:
343 PDEBUG(1, "returning %d", rc);
344 return rc;
345}
346
347static int ovcamchip_detach(struct i2c_client *c)
348{
349 struct ovcamchip *ov = i2c_get_clientdata(c);
350 int rc;
351
352 rc = ov->sops->free(c);
353 if (rc < 0)
354 return rc;
355
356 i2c_detach_client(c);
357
358 kfree(ov);
359 kfree(c);
360 return 0;
361}
362
363static int ovcamchip_command(struct i2c_client *c, unsigned int cmd, void *arg)
364{
365 struct ovcamchip *ov = i2c_get_clientdata(c);
366
367 if (!ov->initialized &&
368 cmd != OVCAMCHIP_CMD_Q_SUBTYPE &&
369 cmd != OVCAMCHIP_CMD_INITIALIZE) {
370 dev_err(&c->dev, "ERROR: Camera chip not initialized yet!\n");
371 return -EPERM;
372 }
373
374 switch (cmd) {
375 case OVCAMCHIP_CMD_Q_SUBTYPE:
376 {
377 *(int *)arg = ov->subtype;
378 return 0;
379 }
380 case OVCAMCHIP_CMD_INITIALIZE:
381 {
382 int rc;
383
384 if (mono == -1)
385 ov->mono = *(int *)arg;
386 else
387 ov->mono = mono;
388
389 if (ov->mono) {
390 if (ov->subtype != CC_OV7620)
391 dev_warn(&c->dev, "Warning: Monochrome not "
392 "implemented for this chip\n");
393 else
394 dev_info(&c->dev, "Initializing chip as "
395 "monochrome\n");
396 }
397
398 rc = ov->sops->init(c);
399 if (rc < 0)
400 return rc;
401
402 ov->initialized = 1;
403 return 0;
404 }
405 default:
406 return ov->sops->command(c, cmd, arg);
407 }
408}
409
410/* ----------------------------------------------------------------------- */
411
412static struct i2c_driver driver = {
413 .owner = THIS_MODULE,
414 .name = "ovcamchip",
415 .id = I2C_DRIVERID_OVCAMCHIP,
416 .class = I2C_CLASS_CAM_DIGITAL,
417 .flags = I2C_DF_NOTIFY,
418 .attach_adapter = ovcamchip_attach,
419 .detach_client = ovcamchip_detach,
420 .command = ovcamchip_command,
421};
422
423static struct i2c_client client_template = {
424 I2C_DEVNAME("(unset)"),
425 .driver = &driver,
426};
427
428static int __init ovcamchip_init(void)
429{
430#ifdef DEBUG
431 ovcamchip_debug = debug;
432#endif
433
434 PINFO(DRIVER_VERSION " : " DRIVER_DESC);
435 return i2c_add_driver(&driver);
436}
437
438static void __exit ovcamchip_exit(void)
439{
440 i2c_del_driver(&driver);
441}
442
443module_init(ovcamchip_init);
444module_exit(ovcamchip_exit);
diff --git a/drivers/media/video/ovcamchip/ovcamchip_priv.h b/drivers/media/video/ovcamchip/ovcamchip_priv.h
new file mode 100644
index 000000000000..575e612a5546
--- /dev/null
+++ b/drivers/media/video/ovcamchip/ovcamchip_priv.h
@@ -0,0 +1,87 @@
1/* OmniVision* camera chip driver private definitions for core code and
2 * chip-specific code
3 *
4 * Copyright (c) 1999-2004 Mark McClelland
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. NO WARRANTY OF ANY KIND is expressed or implied.
10 *
11 * * OmniVision is a trademark of OmniVision Technologies, Inc. This driver
12 * is not sponsored or developed by them.
13 */
14
15#ifndef __LINUX_OVCAMCHIP_PRIV_H
16#define __LINUX_OVCAMCHIP_PRIV_H
17
18#include <media/ovcamchip.h>
19
20#ifdef DEBUG
21extern int ovcamchip_debug;
22#endif
23
24#define PDEBUG(level, fmt, args...) \
25 if (ovcamchip_debug >= (level)) pr_debug("[%s:%d] " fmt "\n", \
26 __FUNCTION__, __LINE__ , ## args)
27
28#define DDEBUG(level, dev, fmt, args...) \
29 if (ovcamchip_debug >= (level)) dev_dbg(dev, "[%s:%d] " fmt "\n", \
30 __FUNCTION__, __LINE__ , ## args)
31
32/* Number of times to retry chip detection. Increase this if you are getting
33 * "Failed to init camera chip" */
34#define I2C_DETECT_RETRIES 10
35
36struct ovcamchip_regvals {
37 unsigned char reg;
38 unsigned char val;
39};
40
41struct ovcamchip_ops {
42 int (*init)(struct i2c_client *);
43 int (*free)(struct i2c_client *);
44 int (*command)(struct i2c_client *, unsigned int, void *);
45};
46
47struct ovcamchip {
48 struct ovcamchip_ops *sops;
49 void *spriv; /* Private data for OV7x10.c etc... */
50 int subtype; /* = SEN_OV7610 etc... */
51 int mono; /* Monochrome chip? (invalid until init) */
52 int initialized; /* OVCAMCHIP_CMD_INITIALIZE was successful */
53};
54
55/* --------------------------------- */
56/* I2C I/O */
57/* --------------------------------- */
58
59static inline int ov_read(struct i2c_client *c, unsigned char reg,
60 unsigned char *value)
61{
62 int rc;
63
64 rc = i2c_smbus_read_byte_data(c, reg);
65 *value = (unsigned char) rc;
66 return rc;
67}
68
69static inline int ov_write(struct i2c_client *c, unsigned char reg,
70 unsigned char value )
71{
72 return i2c_smbus_write_byte_data(c, reg, value);
73}
74
75/* --------------------------------- */
76/* FUNCTION PROTOTYPES */
77/* --------------------------------- */
78
79/* Functions in ovcamchip_core.c */
80
81extern int ov_write_regvals(struct i2c_client *c,
82 struct ovcamchip_regvals *rvals);
83
84extern int ov_write_mask(struct i2c_client *c, unsigned char reg,
85 unsigned char value, unsigned char mask);
86
87#endif