1
2
3
4
5
6
7
8
9
10
11
12#define DEBUG
13
14#include <linux/init.h>
15#include <linux/module.h>
16#include <linux/slab.h>
17#include <linux/delay.h>
18#include <linux/i2c.h>
19#include <media/v4l2-device.h>
20#include <media/v4l2-i2c-drv.h>
21#include "ovcamchip_priv.h"
22
23#define DRIVER_VERSION "v2.27 for Linux 2.6"
24#define DRIVER_AUTHOR "Mark McClelland <mark@alpha.dyndns.org>"
25#define DRIVER_DESC "OV camera chip I2C driver"
26
27#define PINFO(fmt, args...) printk(KERN_INFO "ovcamchip: " fmt "\n" , ## args);
28#define PERROR(fmt, args...) printk(KERN_ERR "ovcamchip: " fmt "\n" , ## args);
29
30#ifdef DEBUG
31int ovcamchip_debug = 0;
32static int debug;
33module_param(debug, int, 0);
34MODULE_PARM_DESC(debug,
35 "Debug level: 0=none, 1=inits, 2=warning, 3=config, 4=functions, 5=all");
36#endif
37
38
39
40
41static int mono = -1;
42module_param(mono, int, 0);
43MODULE_PARM_DESC(mono,
44 "1=chips are monochrome (OVx1xx), 0=force color, -1=autodetect (default)");
45
46MODULE_AUTHOR(DRIVER_AUTHOR);
47MODULE_DESCRIPTION(DRIVER_DESC);
48MODULE_LICENSE("GPL");
49
50
51
52#define GENERIC_REG_ID_HIGH 0x1C
53#define GENERIC_REG_ID_LOW 0x1D
54#define GENERIC_REG_COM_I 0x29
55
56static char *chip_names[NUM_CC_TYPES] = {
57 [CC_UNKNOWN] = "Unknown chip",
58 [CC_OV76BE] = "OV76BE",
59 [CC_OV7610] = "OV7610",
60 [CC_OV7620] = "OV7620",
61 [CC_OV7620AE] = "OV7620AE",
62 [CC_OV6620] = "OV6620",
63 [CC_OV6630] = "OV6630",
64 [CC_OV6630AE] = "OV6630AE",
65 [CC_OV6630AF] = "OV6630AF",
66};
67
68
69
70int ov_write_regvals(struct i2c_client *c, struct ovcamchip_regvals *rvals)
71{
72 int rc;
73
74 while (rvals->reg != 0xff) {
75 rc = ov_write(c, rvals->reg, rvals->val);
76 if (rc < 0)
77 return rc;
78 rvals++;
79 }
80
81 return 0;
82}
83
84
85
86
87
88
89int ov_write_mask(struct i2c_client *c,
90 unsigned char reg,
91 unsigned char value,
92 unsigned char mask)
93{
94 int rc;
95 unsigned char oldval, newval;
96
97 if (mask == 0xff) {
98 newval = value;
99 } else {
100 rc = ov_read(c, reg, &oldval);
101 if (rc < 0)
102 return rc;
103
104 oldval &= (~mask);
105 value &= mask;
106 newval = oldval | value;
107 }
108
109 return ov_write(c, reg, newval);
110}
111
112
113
114
115
116static int init_camchip(struct i2c_client *c)
117{
118 int i, success;
119 unsigned char high, low;
120
121
122 ov_write(c, 0x12, 0x80);
123
124
125 msleep(150);
126
127 for (i = 0, success = 0; i < I2C_DETECT_RETRIES && !success; i++) {
128 if (ov_read(c, GENERIC_REG_ID_HIGH, &high) >= 0) {
129 if (ov_read(c, GENERIC_REG_ID_LOW, &low) >= 0) {
130 if (high == 0x7F && low == 0xA2) {
131 success = 1;
132 continue;
133 }
134 }
135 }
136
137
138 ov_write(c, 0x12, 0x80);
139
140
141 msleep(150);
142
143
144 ov_read(c, 0x00, &low);
145 }
146
147 if (!success)
148 return -EIO;
149
150 PDEBUG(1, "I2C synced in %d attempt(s)", i);
151
152 return 0;
153}
154
155
156static int ov7xx0_detect(struct i2c_client *c)
157{
158 struct ovcamchip *ov = i2c_get_clientdata(c);
159 int rc;
160 unsigned char val;
161
162 PDEBUG(4, "");
163
164
165 rc = ov_read(c, GENERIC_REG_COM_I, &val);
166 if (rc < 0) {
167 PERROR("Error detecting ov7xx0 type");
168 return rc;
169 }
170
171 if ((val & 3) == 3) {
172 PINFO("Camera chip is an OV7610");
173 ov->subtype = CC_OV7610;
174 } else if ((val & 3) == 1) {
175 rc = ov_read(c, 0x15, &val);
176 if (rc < 0) {
177 PERROR("Error detecting ov7xx0 type");
178 return rc;
179 }
180
181 if (val & 1) {
182 PINFO("Camera chip is an OV7620AE");
183
184
185
186 ov->subtype = CC_OV7620;
187 } else {
188 PINFO("Camera chip is an OV76BE");
189 ov->subtype = CC_OV76BE;
190 }
191 } else if ((val & 3) == 0) {
192 PINFO("Camera chip is an OV7620");
193 ov->subtype = CC_OV7620;
194 } else {
195 PERROR("Unknown camera chip version: %d", val & 3);
196 return -ENOSYS;
197 }
198
199 if (ov->subtype == CC_OV76BE)
200 ov->sops = &ov76be_ops;
201 else if (ov->subtype == CC_OV7620)
202 ov->sops = &ov7x20_ops;
203 else
204 ov->sops = &ov7x10_ops;
205
206 return 0;
207}
208
209
210static int ov6xx0_detect(struct i2c_client *c)
211{
212 struct ovcamchip *ov = i2c_get_clientdata(c);
213 int rc;
214 unsigned char val;
215
216 PDEBUG(4, "");
217
218
219 rc = ov_read(c, GENERIC_REG_COM_I, &val);
220 if (rc < 0) {
221 PERROR("Error detecting ov6xx0 type");
222 return -1;
223 }
224
225 if ((val & 3) == 0) {
226 ov->subtype = CC_OV6630;
227 PINFO("Camera chip is an OV6630");
228 } else if ((val & 3) == 1) {
229 ov->subtype = CC_OV6620;
230 PINFO("Camera chip is an OV6620");
231 } else if ((val & 3) == 2) {
232 ov->subtype = CC_OV6630;
233 PINFO("Camera chip is an OV6630AE");
234 } else if ((val & 3) == 3) {
235 ov->subtype = CC_OV6630;
236 PINFO("Camera chip is an OV6630AF");
237 }
238
239 if (ov->subtype == CC_OV6620)
240 ov->sops = &ov6x20_ops;
241 else
242 ov->sops = &ov6x30_ops;
243
244 return 0;
245}
246
247static int ovcamchip_detect(struct i2c_client *c)
248{
249
250
251
252
253
254
255 PDEBUG(3, "Testing for 0V7xx0");
256 if (init_camchip(c) < 0)
257 return -ENODEV;
258
259 if (c->addr & 1) {
260 if (ov7xx0_detect(c) < 0) {
261 PERROR("Failed to init OV7xx0");
262 return -EIO;
263 }
264 return 0;
265 }
266
267 PDEBUG(3, "Testing for 0V6xx0");
268 if (ov6xx0_detect(c) < 0) {
269 PERROR("Failed to init OV6xx0");
270 return -EIO;
271 }
272 return 0;
273}
274
275
276
277static long ovcamchip_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
278{
279 struct ovcamchip *ov = to_ovcamchip(sd);
280 struct i2c_client *c = v4l2_get_subdevdata(sd);
281
282 if (!ov->initialized &&
283 cmd != OVCAMCHIP_CMD_Q_SUBTYPE &&
284 cmd != OVCAMCHIP_CMD_INITIALIZE) {
285 v4l2_err(sd, "Camera chip not initialized yet!\n");
286 return -EPERM;
287 }
288
289 switch (cmd) {
290 case OVCAMCHIP_CMD_Q_SUBTYPE:
291 {
292 *(int *)arg = ov->subtype;
293 return 0;
294 }
295 case OVCAMCHIP_CMD_INITIALIZE:
296 {
297 int rc;
298
299 if (mono == -1)
300 ov->mono = *(int *)arg;
301 else
302 ov->mono = mono;
303
304 if (ov->mono) {
305 if (ov->subtype != CC_OV7620)
306 v4l2_warn(sd, "Monochrome not "
307 "implemented for this chip\n");
308 else
309 v4l2_info(sd, "Initializing chip as "
310 "monochrome\n");
311 }
312
313 rc = ov->sops->init(c);
314 if (rc < 0)
315 return rc;
316
317 ov->initialized = 1;
318 return 0;
319 }
320 default:
321 return ov->sops->command(c, cmd, arg);
322 }
323}
324
325
326
327static const struct v4l2_subdev_core_ops ovcamchip_core_ops = {
328 .ioctl = ovcamchip_ioctl,
329};
330
331static const struct v4l2_subdev_ops ovcamchip_ops = {
332 .core = &ovcamchip_core_ops,
333};
334
335static int ovcamchip_probe(struct i2c_client *client,
336 const struct i2c_device_id *id)
337{
338 struct ovcamchip *ov;
339 struct v4l2_subdev *sd;
340 int rc = 0;
341
342 ov = kzalloc(sizeof *ov, GFP_KERNEL);
343 if (!ov) {
344 rc = -ENOMEM;
345 goto no_ov;
346 }
347 sd = &ov->sd;
348 v4l2_i2c_subdev_init(sd, client, &ovcamchip_ops);
349
350 rc = ovcamchip_detect(client);
351 if (rc < 0)
352 goto error;
353
354 v4l_info(client, "%s found @ 0x%02x (%s)\n",
355 chip_names[ov->subtype], client->addr << 1, client->adapter->name);
356
357 PDEBUG(1, "Camera chip detection complete");
358
359 return rc;
360error:
361 kfree(ov);
362no_ov:
363 PDEBUG(1, "returning %d", rc);
364 return rc;
365}
366
367static int ovcamchip_remove(struct i2c_client *client)
368{
369 struct v4l2_subdev *sd = i2c_get_clientdata(client);
370 struct ovcamchip *ov = to_ovcamchip(sd);
371 int rc;
372
373 v4l2_device_unregister_subdev(sd);
374 rc = ov->sops->free(client);
375 if (rc < 0)
376 return rc;
377
378 kfree(ov);
379 return 0;
380}
381
382
383
384static const struct i2c_device_id ovcamchip_id[] = {
385 { "ovcamchip", 0 },
386 { }
387};
388MODULE_DEVICE_TABLE(i2c, ovcamchip_id);
389
390static struct v4l2_i2c_driver_data v4l2_i2c_data = {
391 .name = "ovcamchip",
392 .probe = ovcamchip_probe,
393 .remove = ovcamchip_remove,
394 .id_table = ovcamchip_id,
395};
396