/* * OmniVision OV7610/OV7110 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__ #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 "ov511.h" /* OV7610 registers */ #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 */ #define REG_CLOCK 0x11 /* polarity/clock prescaler */ #define REG_COM_A 0x12 /* misc common regs */ #define REG_COM_B 0x13 /* misc common regs */ #define REG_COM_C 0x14 /* misc common regs */ #define REG_COM_D 0x15 /* misc common regs */ #define REG_FIELD_DIVIDE 0x16 /* field interval/mode settings */ #define REG_HWIN_START 0x17 /* horizontal window start */ #define REG_HWIN_END 0x18 /* horizontal window end */ #define REG_VWIN_START 0x19 /* vertical window start */ #define REG_VWIN_END 0x1A /* vertical window end */ #define REG_PIXEL_SHIFT 0x1B /* pixel shift */ #define REG_ID_HIGH 0x1C /* manufacturer ID MSB */ #define REG_ID_LOW 0x1D /* manufacturer ID LSB */ /* 0e-0f reserved */ #define REG_COM_E 0x20 /* misc common regs */ #define REG_YOFFSET 0x21 /* Y channel offset */ #define REG_UOFFSET 0x22 /* U channel offset */ /* 23 reserved */ #define REG_ECW 0x24 /* Exposure white level for AEC */ #define REG_ECB 0x25 /* Exposure black level for AEC */ #define REG_COM_F 0x26 /* misc settings */ #define REG_COM_G 0x27 /* misc settings */ #define REG_COM_H 0x28 /* misc settings */ #define REG_COM_I 0x29 /* misc settings */ #define REG_FRAMERATE_H 0x2A /* frame rate MSB + misc */ #define REG_FRAMERATE_L 0x2B /* frame rate LSB */ #define REG_ALC 0x2C /* Auto Level Control settings */ #define REG_COM_J 0x2D /* misc settings */ #define REG_VOFFSET 0x2E /* V channel offset adjustment */ #define REG_ARRAY_BIAS 0x2F /* Array bias -- don't change */ /* 30-32 reserved */ #define REG_YGAMMA 0x33 /* misc gamma settings (7:6) */ #define REG_BIAS_ADJUST 0x34 /* misc bias settings */ #define REG_COM_L 0x35 /* misc settings */ /* 36-37 reserved */ #define REG_COM_K 0x38 /* misc registers */ extern int debug; /* Exists in ov511.c and ov518.c */ /* ******************** 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; } /* ************************************************************** */ /* Lawrence Glaister reports: * * Register 0x0f in the 7610 has the following effects: * * 0x85 (AEC method 1): Best overall, good contrast range * 0x45 (AEC method 2): Very overexposed * 0xa5 (spec sheet default): Ok, but the black level is * shifted resulting in loss of contrast * 0x05 (old driver setting): very overexposed, too much * contrast */ static struct ovsensor_regvals regvalsNorm7x10[] = { { 0x10, 0xff }, { 0x16, 0x06 }, { 0x28, 0x24 }, { 0x2b, 0xac }, { 0x12, 0x00 }, { 0x38, 0x81 }, { 0x28, 0x24 }, /* 0c */ { 0x0f, 0x85 }, /* lg's setting */ { 0x15, 0x01 }, { 0x20, 0x1c }, { 0x23, 0x2a }, { 0x24, 0x10 }, { 0x25, 0x8a }, { 0x26, 0xa2 }, { 0x27, 0xc2 }, { 0x2a, 0x04 }, { 0x2c, 0xfe }, { 0x2d, 0x93 }, { 0x30, 0x71 }, { 0x31, 0x60 }, { 0x32, 0x26 }, { 0x33, 0x20 }, { 0x34, 0x48 }, { 0x12, 0x24 }, { 0x11, 0x01 }, { 0x0c, 0x24 }, { 0x0d, 0x24 }, { 0xff, 0xff }, /* END MARKER */ }; /* This initializes the OV7x10 sensor and relevant variables. */ static int ov7x10_configure(struct usb_ov511 *ov) { int rc; PDEBUG(4, "entered"); /* Set sensor-specific vars */ ov->maxwidth = 640; ov->maxheight = 480; ov->minwidth = 64; ov->minheight = 48; // FIXME: These do not match the actual settings yet ov->brightness = 0x80 << 8; ov->contrast = 0x80 << 8; ov->colour = 0x80 << 8; ov->hue = 0x80 << 8; rc = ovsensor_write_regvals(ov, regvalsNorm7x10); return rc; } static int ov7x10_command(struct usb_ov511 *ov, int cmd, void *arg) { struct ov_i2c *i2c = ov->i2c; int rc; unsigned char val = 0; PDEBUG(3, "cmd=%d", cmd); switch (cmd) { case OVSENSOR_CMD_S_CONT: rc = i2c->w(ov, REG_CNT, *((unsigned short *)arg) >> 8); break; case OVSENSOR_CMD_G_CONT: rc = i2c->r(ov, REG_CNT, &val); *((unsigned short *)arg) = val << 8; break; case OVSENSOR_CMD_S_BRIGHT: rc = i2c->w(ov, REG_BRT, *((unsigned short *)arg) >> 8); break; case OVSENSOR_CMD_G_BRIGHT: rc = i2c->r(ov, REG_BRT, &val); *((unsigned short *)arg) = val << 8; break; case OVSENSOR_CMD_S_SAT: rc = i2c->w(ov, REG_SAT, *((unsigned short *)arg) >> 8); break; case OVSENSOR_CMD_G_SAT: rc = i2c->r(ov, REG_SAT, &val); *((unsigned short *)arg) = val << 8; break; case OVSENSOR_CMD_S_HUE: rc = i2c->w(ov, REG_RED, 0xFF - (*((unsigned short *)arg) >> 8)); if (rc < 0) goto out; rc = i2c->w(ov, REG_BLUE, *((unsigned short *)arg) >> 8); break; case OVSENSOR_CMD_G_HUE: rc = i2c->r(ov, REG_BLUE, &val); *((unsigned short *)arg) = val << 8; break; case OVSENSOR_CMD_S_EXP: rc = i2c->w(ov, REG_EXP, *((unsigned char *)arg)); break; case OVSENSOR_CMD_G_EXP: rc = i2c->r(ov, REG_EXP, &val); *((unsigned char *)arg) = val; break; case OVSENSOR_CMD_S_FREQ: { int sixty = *(int *)arg == 60; rc = ov->i2c->w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80); if (rc < 0) goto out; rc = ov->i2c->w(ov, 0x2b, sixty?0x00:0xac); if (rc < 0) goto out; rc = ov->i2c->w_mask(ov, 0x13, 0x10, 0x10); if (rc < 0) goto out; rc = ov->i2c->w_mask(ov, 0x13, 0x00, 0x10); break; } case OVSENSOR_CMD_BANDFILT: rc = ov->i2c->w_mask(ov, 0x2d, (*(int *)arg)?0x04:0x00, 0x04); break; case OVSENSOR_CMD_AUTOBRIGHT: rc = ov->i2c->w_mask(ov, 0x2d, (*(int *)arg)?0x10:0x00, 0x10); break; case OVSENSOR_CMD_AUTOEXP: rc = ov->i2c->w_mask(ov, 0x29, (*(int *)arg)?0x00:0x80, 0x80); break; // case OVSENSOR_CMD_BACKLIGHT: case OVSENSOR_CMD_MIRROR: rc = ov->i2c->w_mask(ov, 0x12, (*(int *)arg)?0x40:0x00, 0x40); break; default: PDEBUG(2, "command not supported: %d", cmd); return -EPERM; } out: return rc; } struct ovsensor_ops ov7x10_ops = { configure: ov7x10_configure, command: ov7x10_command, };