aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/ovcamchip/ov76be.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/ovcamchip/ov76be.c')
-rw-r--r--drivers/media/video/ovcamchip/ov76be.c303
1 files changed, 303 insertions, 0 deletions
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};