Committer: Michael Beasley <mike@snafu.setup>
[mikesnafu-overlay.git] / drivers / media / video / ovcamchip / ov76be.c
blob11f6be924d8b4d4e42cbfe732d1acbec988c20b3
1 /* OmniVision OV76BE Camera Chip Support Code
3 * Copyright (c) 1999-2004 Mark McClelland <mark@alpha.dyndns.org>
4 * http://alpha.dyndns.org/ov511/
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.
12 #define DEBUG
14 #include <linux/slab.h>
15 #include "ovcamchip_priv.h"
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 */
49 /* Window parameters */
50 #define HWSBASE 0x38
51 #define HWEBASE 0x3a
52 #define VWSBASE 0x05
53 #define VWEBASE 0x05
55 struct ov76be {
56 int auto_brt;
57 int auto_exp;
58 int bandfilt;
59 int mirror;
62 /* NOTE: These are the same as the 7x10 settings, but should eventually be
63 * optimized for the OV76BE */
64 static 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 */
95 /* This initializes the OV76be camera chip and relevant variables. */
96 static int ov76be_init(struct i2c_client *c)
98 struct ovcamchip *ov = i2c_get_clientdata(c);
99 struct ov76be *s;
100 int rc;
102 DDEBUG(4, &c->dev, "entered");
104 rc = ov_write_regvals(c, regvals_init_76be);
105 if (rc < 0)
106 return rc;
108 ov->spriv = s = kzalloc(sizeof *s, GFP_KERNEL);
109 if (!s)
110 return -ENOMEM;
112 s->auto_brt = 1;
113 s->auto_exp = 1;
115 return rc;
118 static int ov76be_free(struct i2c_client *c)
120 struct ovcamchip *ov = i2c_get_clientdata(c);
122 kfree(ov->spriv);
123 return 0;
126 static int ov76be_set_control(struct i2c_client *c,
127 struct ovcamchip_control *ctl)
129 struct ovcamchip *ov = i2c_get_clientdata(c);
130 struct ov76be *s = ov->spriv;
131 int rc;
132 int v = ctl->value;
134 switch (ctl->id) {
135 case OVCAMCHIP_CID_BRIGHT:
136 rc = ov_write(c, REG_BRT, v >> 8);
137 break;
138 case OVCAMCHIP_CID_SAT:
139 rc = ov_write(c, REG_SAT, v >> 8);
140 break;
141 case OVCAMCHIP_CID_EXP:
142 rc = ov_write(c, REG_EXP, v);
143 break;
144 case OVCAMCHIP_CID_FREQ:
146 int sixty = (v == 60);
148 rc = ov_write_mask(c, 0x2a, sixty?0x00:0x80, 0x80);
149 if (rc < 0)
150 goto out;
152 rc = ov_write(c, 0x2b, sixty?0x00:0xac);
153 if (rc < 0)
154 goto out;
156 rc = ov_write_mask(c, 0x76, 0x01, 0x01);
157 break;
159 case OVCAMCHIP_CID_BANDFILT:
160 rc = ov_write_mask(c, 0x2d, v?0x04:0x00, 0x04);
161 s->bandfilt = v;
162 break;
163 case OVCAMCHIP_CID_AUTOBRIGHT:
164 rc = ov_write_mask(c, 0x2d, v?0x10:0x00, 0x10);
165 s->auto_brt = v;
166 break;
167 case OVCAMCHIP_CID_AUTOEXP:
168 rc = ov_write_mask(c, 0x13, v?0x01:0x00, 0x01);
169 s->auto_exp = v;
170 break;
171 case OVCAMCHIP_CID_MIRROR:
172 rc = ov_write_mask(c, 0x12, v?0x40:0x00, 0x40);
173 s->mirror = v;
174 break;
175 default:
176 DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
177 return -EPERM;
180 out:
181 DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, v, rc);
182 return rc;
185 static int ov76be_get_control(struct i2c_client *c,
186 struct ovcamchip_control *ctl)
188 struct ovcamchip *ov = i2c_get_clientdata(c);
189 struct ov76be *s = ov->spriv;
190 int rc = 0;
191 unsigned char val = 0;
193 switch (ctl->id) {
194 case OVCAMCHIP_CID_BRIGHT:
195 rc = ov_read(c, REG_BRT, &val);
196 ctl->value = val << 8;
197 break;
198 case OVCAMCHIP_CID_SAT:
199 rc = ov_read(c, REG_SAT, &val);
200 ctl->value = val << 8;
201 break;
202 case OVCAMCHIP_CID_EXP:
203 rc = ov_read(c, REG_EXP, &val);
204 ctl->value = val;
205 break;
206 case OVCAMCHIP_CID_BANDFILT:
207 ctl->value = s->bandfilt;
208 break;
209 case OVCAMCHIP_CID_AUTOBRIGHT:
210 ctl->value = s->auto_brt;
211 break;
212 case OVCAMCHIP_CID_AUTOEXP:
213 ctl->value = s->auto_exp;
214 break;
215 case OVCAMCHIP_CID_MIRROR:
216 ctl->value = s->mirror;
217 break;
218 default:
219 DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
220 return -EPERM;
223 DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, ctl->value, rc);
224 return rc;
227 static int ov76be_mode_init(struct i2c_client *c, struct ovcamchip_window *win)
229 int qvga = win->quarter;
231 /******** QVGA-specific regs ********/
233 ov_write(c, 0x14, qvga?0xa4:0x84);
235 /******** Palette-specific regs ********/
237 if (win->format == VIDEO_PALETTE_GREY) {
238 ov_write_mask(c, 0x0e, 0x40, 0x40);
239 ov_write_mask(c, 0x13, 0x20, 0x20);
240 } else {
241 ov_write_mask(c, 0x0e, 0x00, 0x40);
242 ov_write_mask(c, 0x13, 0x00, 0x20);
245 /******** Clock programming ********/
247 ov_write(c, 0x11, win->clockdiv);
249 /******** Resolution-specific ********/
251 if (win->width == 640 && win->height == 480)
252 ov_write(c, 0x35, 0x9e);
253 else
254 ov_write(c, 0x35, 0x1e);
256 return 0;
259 static int ov76be_set_window(struct i2c_client *c, struct ovcamchip_window *win)
261 int ret, hwscale, vwscale;
263 ret = ov76be_mode_init(c, win);
264 if (ret < 0)
265 return ret;
267 if (win->quarter) {
268 hwscale = 1;
269 vwscale = 0;
270 } else {
271 hwscale = 2;
272 vwscale = 1;
275 ov_write(c, 0x17, HWSBASE + (win->x >> hwscale));
276 ov_write(c, 0x18, HWEBASE + ((win->x + win->width) >> hwscale));
277 ov_write(c, 0x19, VWSBASE + (win->y >> vwscale));
278 ov_write(c, 0x1a, VWEBASE + ((win->y + win->height) >> vwscale));
280 return 0;
283 static int ov76be_command(struct i2c_client *c, unsigned int cmd, void *arg)
285 switch (cmd) {
286 case OVCAMCHIP_CMD_S_CTRL:
287 return ov76be_set_control(c, arg);
288 case OVCAMCHIP_CMD_G_CTRL:
289 return ov76be_get_control(c, arg);
290 case OVCAMCHIP_CMD_S_MODE:
291 return ov76be_set_window(c, arg);
292 default:
293 DDEBUG(2, &c->dev, "command not supported: %d", cmd);
294 return -ENOIOCTLCMD;
298 struct ovcamchip_ops ov76be_ops = {
299 .init = ov76be_init,
300 .free = ov76be_free,
301 .command = ov76be_command,