/* * OmniVision OV7620/OV7120 Camera Chip Support Code * * Copyright (c) 1999-2002 Mark McClelland * http://alpha.dyndns.org/ov511/ * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* This file is not a module yet */ #define __NO_VERSION__ /* The kernel Makefile defines this when built with kernel */ #if defined(OUTSIDE_KERNEL) #if !defined(EXPORT_SYMTAB) #define EXPORT_SYMTAB #endif #include #if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) #define MODVERSIONS #endif #include #ifdef MODVERSIONS #include #endif #else #include #include #endif #include #include "ov511.h" /* These may not be correct!! They are only here to make the code compile. */ #define REG_GAIN 0x00 /* gain setting (5:0) */ #define REG_BLUE 0x01 /* blue channel balance */ #define REG_RED 0x02 /* red channel balance */ #define REG_SAT 0x03 /* saturation */ /* 04 reserved */ #define REG_CNT 0x05 /* Y contrast */ #define REG_BRT 0x06 /* Y brightness */ /* 08-0b reserved */ #define REG_BLUE_BIAS 0x0C /* blue channel bias (5:0) */ #define REG_RED_BIAS 0x0D /* read channel bias (5:0) */ #define REG_GAMMA_COEFF 0x0E /* gamma settings */ #define REG_WB_RANGE 0x0F /* AEC/ALC/S-AWB settings */ #define REG_EXP 0x10 /* manual exposure setting */ extern int debug; /* Exists in ov511.c and ov518.c */ struct ov7x20 { struct ov_i2c *i2c; int auto_brt; int auto_exp; int backlight; int bandfilt; int mirror; }; /* ******************** Common functions ************************ */ static int ovsensor_write_regvals(struct usb_ov511 *ov, struct ovsensor_regvals *rvals) { int rc; while (rvals->reg != 0xff) { rc = ov->i2c->w(ov, rvals->reg, rvals->val); if (rc < 0) return rc; rvals++; } return 0; } /* ************************************************************** */ static struct ovsensor_regvals regvalsNorm7x20[] = { { 0x00, 0x00 }, { 0x01, 0x80 }, { 0x02, 0x80 }, { 0x03, 0xc0 }, { 0x06, 0x60 }, { 0x07, 0x00 }, { 0x0c, 0x24 }, { 0x0c, 0x24 }, { 0x0d, 0x24 }, { 0x11, 0x01 }, { 0x12, 0x24 }, { 0x13, 0x01 }, { 0x14, 0x84 }, { 0x15, 0x01 }, { 0x16, 0x03 }, { 0x17, 0x2f }, { 0x18, 0xcf }, { 0x19, 0x06 }, { 0x1a, 0xf5 }, { 0x1b, 0x00 }, { 0x20, 0x18 }, { 0x21, 0x80 }, { 0x22, 0x80 }, { 0x23, 0x00 }, { 0x26, 0xa2 }, { 0x27, 0xea }, { 0x28, 0x20 }, { 0x29, 0x00 }, { 0x2a, 0x10 }, { 0x2b, 0x00 }, { 0x2c, 0x88 }, { 0x2d, 0x91 }, { 0x2e, 0x80 }, { 0x2f, 0x44 }, { 0x60, 0x27 }, { 0x61, 0x02 }, { 0x62, 0x5f }, { 0x63, 0xd5 }, { 0x64, 0x57 }, { 0x65, 0x83 }, { 0x66, 0x55 }, { 0x67, 0x92 }, { 0x68, 0xcf }, { 0x69, 0x76 }, { 0x6a, 0x22 }, { 0x6b, 0x00 }, { 0x6c, 0x02 }, { 0x6d, 0x44 }, { 0x6e, 0x80 }, { 0x6f, 0x1d }, { 0x70, 0x8b }, { 0x71, 0x00 }, { 0x72, 0x14 }, { 0x73, 0x54 }, { 0x74, 0x00 }, { 0x75, 0x8e }, { 0x76, 0x00 }, { 0x77, 0xff }, { 0x78, 0x80 }, { 0x79, 0x80 }, { 0x7a, 0x80 }, { 0x7b, 0xe2 }, { 0x7c, 0x00 }, { 0xff, 0xff }, /* END MARKER */ }; /* This initializes the OV7x20 sensor and relevant variables. */ static int ov7x20_configure(struct usb_ov511 *ov) { struct ov7x20 *s; int rc; PDEBUG(4, "entered"); ov->spriv = s = kmalloc(sizeof *s, GFP_KERNEL); if (!s) return -ENOMEM; memset(s, 0, sizeof *s); s->i2c = ov->i2c; s->auto_brt = 1; s->auto_exp = 1; /* Set sensor-specific vars */ ov->maxwidth = 640; ov->maxheight = 480; ov->minwidth = 64; ov->minheight = 48; rc = ovsensor_write_regvals(ov, regvalsNorm7x20); return rc; } static int ov7x20_command(struct usb_ov511 *ov, int cmd, int *arg) { struct ov7x20 *s = ov->spriv; struct ov_i2c *i2c = s->i2c; int rc; unsigned char val = 0; switch (cmd) { case OVSENSOR_CMD_S_CONT: { unsigned char ctab[] = { 0x01, 0x05, 0x09, 0x11, 0x15, 0x35, 0x37, 0x57, 0x5b, 0xa5, 0xa7, 0xc7, 0xc9, 0xcf, 0xef, 0xff }; /* Use Y gamma control instead. Bit 0 enables it. */ rc = i2c->w(ov, 0x64, ctab[*arg >> 12]); break; } case OVSENSOR_CMD_G_CONT: rc = i2c->r(ov, 0x64, &val); *arg = (val & 0xfe) << 8; break; case OVSENSOR_CMD_S_BRIGHT: /* 7620 doesn't like manual changes when in auto mode */ if (!s->auto_brt) rc = i2c->w(ov, REG_BRT, *arg >> 8); else rc = 0; break; case OVSENSOR_CMD_G_BRIGHT: rc = i2c->r(ov, REG_BRT, &val); *arg = val << 8; break; case OVSENSOR_CMD_S_SAT: rc = i2c->w(ov, REG_SAT, *arg >> 8); break; case OVSENSOR_CMD_G_SAT: rc = i2c->r(ov, REG_SAT, &val); *arg = val << 8; break; // FIXME: Setting hue not implemented because it causes problems // case OVSENSOR_CMD_S_HUE: // case OVSENSOR_CMD_G_HUE: case OVSENSOR_CMD_S_EXP: rc = i2c->w(ov, REG_EXP, *arg); break; case OVSENSOR_CMD_G_EXP: rc = i2c->r(ov, REG_EXP, &val); *arg = val; break; case OVSENSOR_CMD_S_FREQ: { int sixty = *arg == 60; rc = i2c->w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80); if (rc < 0) goto out; rc = i2c->w(ov, 0x2b, sixty?0x00:0xac); if (rc < 0) goto out; rc = i2c->w_mask(ov, 0x76, 0x01, 0x01); break; } case OVSENSOR_CMD_BANDFILT: rc = i2c->w_mask(ov, 0x2d, (*arg)?0x04:0x00, 0x04); s->bandfilt = *arg; break; case OVSENSOR_CMD_AUTOBRIGHT: rc = i2c->w_mask(ov, 0x2d, (*arg)?0x10:0x00, 0x10); s->auto_brt = *arg; break; case OVSENSOR_CMD_AUTOEXP: rc = i2c->w_mask(ov, 0x13, (*arg)?0x01:0x00, 0x01); s->auto_exp = *arg; break; case OVSENSOR_CMD_BACKLIGHT: { int enable = *arg; rc = i2c->w_mask(ov, 0x68, enable?0xe0:0xc0, 0xe0); if (rc < 0) goto out; rc = i2c->w_mask(ov, 0x29, enable?0x08:0x00, 0x08); if (rc < 0) goto out; rc = i2c->w_mask(ov, 0x28, enable?0x02:0x00, 0x02); s->backlight = enable; break; } case OVSENSOR_CMD_MIRROR: rc = i2c->w_mask(ov, 0x12, (*arg)?0x40:0x00, 0x40); s->mirror = *arg; break; default: PDEBUG(2, "command not supported: %d", cmd); return -EPERM; } out: PDEBUG(3, "cmd=%d, arg=%d, rc=%d", cmd, *arg, rc); return rc; } struct ovsensor_ops ov7x20_ops = { configure: ov7x20_configure, command: ov7x20_command, };