1fd9871f7SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2cba862dcSMauro Carvalho Chehab /*
30c0d06caSMauro Carvalho Chehab * OV519 driver
40c0d06caSMauro Carvalho Chehab *
50c0d06caSMauro Carvalho Chehab * Copyright (C) 2008-2011 Jean-François Moine <moinejf@free.fr>
60c0d06caSMauro Carvalho Chehab * Copyright (C) 2009 Hans de Goede <hdegoede@redhat.com>
70c0d06caSMauro Carvalho Chehab *
80c0d06caSMauro Carvalho Chehab * This module is adapted from the ov51x-jpeg package, which itself
90c0d06caSMauro Carvalho Chehab * was adapted from the ov511 driver.
100c0d06caSMauro Carvalho Chehab *
110c0d06caSMauro Carvalho Chehab * Original copyright for the ov511 driver is:
120c0d06caSMauro Carvalho Chehab *
130c0d06caSMauro Carvalho Chehab * Copyright (c) 1999-2006 Mark W. McClelland
140c0d06caSMauro Carvalho Chehab * Support for OV519, OV8610 Copyright (c) 2003 Joerg Heckenbach
150c0d06caSMauro Carvalho Chehab * Many improvements by Bret Wallach <bwallac1@san.rr.com>
160c0d06caSMauro Carvalho Chehab * Color fixes by by Orion Sky Lawlor <olawlor@acm.org> (2/26/2000)
170c0d06caSMauro Carvalho Chehab * OV7620 fixes by Charl P. Botha <cpbotha@ieee.org>
180c0d06caSMauro Carvalho Chehab * Changes by Claudio Matsuoka <claudio@conectiva.com>
190c0d06caSMauro Carvalho Chehab *
200c0d06caSMauro Carvalho Chehab * ov51x-jpeg original copyright is:
210c0d06caSMauro Carvalho Chehab *
220c0d06caSMauro Carvalho Chehab * Copyright (c) 2004-2007 Romain Beauxis <toots@rastageeks.org>
230c0d06caSMauro Carvalho Chehab * Support for OV7670 sensors was contributed by Sam Skipsey <aoanla@yahoo.com>
240c0d06caSMauro Carvalho Chehab */
250c0d06caSMauro Carvalho Chehab
260c0d06caSMauro Carvalho Chehab #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
270c0d06caSMauro Carvalho Chehab
280c0d06caSMauro Carvalho Chehab #define MODULE_NAME "ov519"
290c0d06caSMauro Carvalho Chehab
300c0d06caSMauro Carvalho Chehab #include <linux/input.h>
310c0d06caSMauro Carvalho Chehab #include "gspca.h"
320c0d06caSMauro Carvalho Chehab
330c0d06caSMauro Carvalho Chehab /* The jpeg_hdr is used by w996Xcf only */
340c0d06caSMauro Carvalho Chehab /* The CONEX_CAM define for jpeg.h needs renaming, now its used here too */
350c0d06caSMauro Carvalho Chehab #define CONEX_CAM
360c0d06caSMauro Carvalho Chehab #include "jpeg.h"
370c0d06caSMauro Carvalho Chehab
380c0d06caSMauro Carvalho Chehab MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
390c0d06caSMauro Carvalho Chehab MODULE_DESCRIPTION("OV519 USB Camera Driver");
400c0d06caSMauro Carvalho Chehab MODULE_LICENSE("GPL");
410c0d06caSMauro Carvalho Chehab
420c0d06caSMauro Carvalho Chehab /* global parameters */
430c0d06caSMauro Carvalho Chehab static int frame_rate;
440c0d06caSMauro Carvalho Chehab
450c0d06caSMauro Carvalho Chehab /* Number of times to retry a failed I2C transaction. Increase this if you
460c0d06caSMauro Carvalho Chehab * are getting "Failed to read sensor ID..." */
470c0d06caSMauro Carvalho Chehab static int i2c_detect_tries = 10;
480c0d06caSMauro Carvalho Chehab
490c0d06caSMauro Carvalho Chehab /* ov519 device descriptor */
500c0d06caSMauro Carvalho Chehab struct sd {
510c0d06caSMauro Carvalho Chehab struct gspca_dev gspca_dev; /* !! must be the first item */
520c0d06caSMauro Carvalho Chehab
530c0d06caSMauro Carvalho Chehab struct v4l2_ctrl *jpegqual;
540c0d06caSMauro Carvalho Chehab struct v4l2_ctrl *freq;
550c0d06caSMauro Carvalho Chehab struct { /* h/vflip control cluster */
560c0d06caSMauro Carvalho Chehab struct v4l2_ctrl *hflip;
570c0d06caSMauro Carvalho Chehab struct v4l2_ctrl *vflip;
580c0d06caSMauro Carvalho Chehab };
590c0d06caSMauro Carvalho Chehab struct { /* autobrightness/brightness control cluster */
600c0d06caSMauro Carvalho Chehab struct v4l2_ctrl *autobright;
610c0d06caSMauro Carvalho Chehab struct v4l2_ctrl *brightness;
620c0d06caSMauro Carvalho Chehab };
630c0d06caSMauro Carvalho Chehab
64b82180dbSHans de Goede u8 revision;
65b82180dbSHans de Goede
660c0d06caSMauro Carvalho Chehab u8 packet_nr;
670c0d06caSMauro Carvalho Chehab
680c0d06caSMauro Carvalho Chehab char bridge;
690c0d06caSMauro Carvalho Chehab #define BRIDGE_OV511 0
700c0d06caSMauro Carvalho Chehab #define BRIDGE_OV511PLUS 1
710c0d06caSMauro Carvalho Chehab #define BRIDGE_OV518 2
720c0d06caSMauro Carvalho Chehab #define BRIDGE_OV518PLUS 3
730c0d06caSMauro Carvalho Chehab #define BRIDGE_OV519 4 /* = ov530 */
740c0d06caSMauro Carvalho Chehab #define BRIDGE_OVFX2 5
750c0d06caSMauro Carvalho Chehab #define BRIDGE_W9968CF 6
760c0d06caSMauro Carvalho Chehab #define BRIDGE_MASK 7
770c0d06caSMauro Carvalho Chehab
780c0d06caSMauro Carvalho Chehab char invert_led;
790c0d06caSMauro Carvalho Chehab #define BRIDGE_INVERT_LED 8
800c0d06caSMauro Carvalho Chehab
810c0d06caSMauro Carvalho Chehab char snapshot_pressed;
820c0d06caSMauro Carvalho Chehab char snapshot_needs_reset;
830c0d06caSMauro Carvalho Chehab
840c0d06caSMauro Carvalho Chehab /* Determined by sensor type */
850c0d06caSMauro Carvalho Chehab u8 sif;
860c0d06caSMauro Carvalho Chehab
870c0d06caSMauro Carvalho Chehab #define QUALITY_MIN 50
880c0d06caSMauro Carvalho Chehab #define QUALITY_MAX 70
890c0d06caSMauro Carvalho Chehab #define QUALITY_DEF 50
900c0d06caSMauro Carvalho Chehab
910c0d06caSMauro Carvalho Chehab u8 stopped; /* Streaming is temporarily paused */
920c0d06caSMauro Carvalho Chehab u8 first_frame;
930c0d06caSMauro Carvalho Chehab
940c0d06caSMauro Carvalho Chehab u8 frame_rate; /* current Framerate */
950c0d06caSMauro Carvalho Chehab u8 clockdiv; /* clockdiv override */
960c0d06caSMauro Carvalho Chehab
970c0d06caSMauro Carvalho Chehab s8 sensor; /* Type of image sensor chip (SEN_*) */
980c0d06caSMauro Carvalho Chehab
990c0d06caSMauro Carvalho Chehab u8 sensor_addr;
1000c0d06caSMauro Carvalho Chehab u16 sensor_width;
1010c0d06caSMauro Carvalho Chehab u16 sensor_height;
1020c0d06caSMauro Carvalho Chehab s16 sensor_reg_cache[256];
1030c0d06caSMauro Carvalho Chehab
1040c0d06caSMauro Carvalho Chehab u8 jpeg_hdr[JPEG_HDR_SZ];
1050c0d06caSMauro Carvalho Chehab };
1060c0d06caSMauro Carvalho Chehab enum sensors {
1070c0d06caSMauro Carvalho Chehab SEN_OV2610,
1080c0d06caSMauro Carvalho Chehab SEN_OV2610AE,
1090c0d06caSMauro Carvalho Chehab SEN_OV3610,
1100c0d06caSMauro Carvalho Chehab SEN_OV6620,
1110c0d06caSMauro Carvalho Chehab SEN_OV6630,
1120c0d06caSMauro Carvalho Chehab SEN_OV66308AF,
1130c0d06caSMauro Carvalho Chehab SEN_OV7610,
1140c0d06caSMauro Carvalho Chehab SEN_OV7620,
1150c0d06caSMauro Carvalho Chehab SEN_OV7620AE,
1160c0d06caSMauro Carvalho Chehab SEN_OV7640,
1170c0d06caSMauro Carvalho Chehab SEN_OV7648,
1180c0d06caSMauro Carvalho Chehab SEN_OV7660,
1190c0d06caSMauro Carvalho Chehab SEN_OV7670,
1200c0d06caSMauro Carvalho Chehab SEN_OV76BE,
1210c0d06caSMauro Carvalho Chehab SEN_OV8610,
1220c0d06caSMauro Carvalho Chehab SEN_OV9600,
1230c0d06caSMauro Carvalho Chehab };
1240c0d06caSMauro Carvalho Chehab
1250c0d06caSMauro Carvalho Chehab /* Note this is a bit of a hack, but the w9968cf driver needs the code for all
1260c0d06caSMauro Carvalho Chehab the ov sensors which is already present here. When we have the time we
1270c0d06caSMauro Carvalho Chehab really should move the sensor drivers to v4l2 sub drivers. */
1280c0d06caSMauro Carvalho Chehab #include "w996Xcf.c"
1290c0d06caSMauro Carvalho Chehab
1300c0d06caSMauro Carvalho Chehab /* table of the disabled controls */
1310c0d06caSMauro Carvalho Chehab struct ctrl_valid {
13250c457a9SEmil Goode unsigned int has_brightness:1;
13350c457a9SEmil Goode unsigned int has_contrast:1;
13450c457a9SEmil Goode unsigned int has_exposure:1;
13550c457a9SEmil Goode unsigned int has_autogain:1;
13650c457a9SEmil Goode unsigned int has_sat:1;
13750c457a9SEmil Goode unsigned int has_hvflip:1;
13850c457a9SEmil Goode unsigned int has_autobright:1;
13950c457a9SEmil Goode unsigned int has_freq:1;
1400c0d06caSMauro Carvalho Chehab };
1410c0d06caSMauro Carvalho Chehab
1420c0d06caSMauro Carvalho Chehab static const struct ctrl_valid valid_controls[] = {
1430c0d06caSMauro Carvalho Chehab [SEN_OV2610] = {
1440c0d06caSMauro Carvalho Chehab .has_exposure = 1,
1450c0d06caSMauro Carvalho Chehab .has_autogain = 1,
1460c0d06caSMauro Carvalho Chehab },
1470c0d06caSMauro Carvalho Chehab [SEN_OV2610AE] = {
1480c0d06caSMauro Carvalho Chehab .has_exposure = 1,
1490c0d06caSMauro Carvalho Chehab .has_autogain = 1,
1500c0d06caSMauro Carvalho Chehab },
1510c0d06caSMauro Carvalho Chehab [SEN_OV3610] = {
1520c0d06caSMauro Carvalho Chehab /* No controls */
1530c0d06caSMauro Carvalho Chehab },
1540c0d06caSMauro Carvalho Chehab [SEN_OV6620] = {
1550c0d06caSMauro Carvalho Chehab .has_brightness = 1,
1560c0d06caSMauro Carvalho Chehab .has_contrast = 1,
1570c0d06caSMauro Carvalho Chehab .has_sat = 1,
1580c0d06caSMauro Carvalho Chehab .has_autobright = 1,
1590c0d06caSMauro Carvalho Chehab .has_freq = 1,
1600c0d06caSMauro Carvalho Chehab },
1610c0d06caSMauro Carvalho Chehab [SEN_OV6630] = {
1620c0d06caSMauro Carvalho Chehab .has_brightness = 1,
1630c0d06caSMauro Carvalho Chehab .has_contrast = 1,
1640c0d06caSMauro Carvalho Chehab .has_sat = 1,
1650c0d06caSMauro Carvalho Chehab .has_autobright = 1,
1660c0d06caSMauro Carvalho Chehab .has_freq = 1,
1670c0d06caSMauro Carvalho Chehab },
1680c0d06caSMauro Carvalho Chehab [SEN_OV66308AF] = {
1690c0d06caSMauro Carvalho Chehab .has_brightness = 1,
1700c0d06caSMauro Carvalho Chehab .has_contrast = 1,
1710c0d06caSMauro Carvalho Chehab .has_sat = 1,
1720c0d06caSMauro Carvalho Chehab .has_autobright = 1,
1730c0d06caSMauro Carvalho Chehab .has_freq = 1,
1740c0d06caSMauro Carvalho Chehab },
1750c0d06caSMauro Carvalho Chehab [SEN_OV7610] = {
1760c0d06caSMauro Carvalho Chehab .has_brightness = 1,
1770c0d06caSMauro Carvalho Chehab .has_contrast = 1,
1780c0d06caSMauro Carvalho Chehab .has_sat = 1,
1790c0d06caSMauro Carvalho Chehab .has_autobright = 1,
1800c0d06caSMauro Carvalho Chehab .has_freq = 1,
1810c0d06caSMauro Carvalho Chehab },
1820c0d06caSMauro Carvalho Chehab [SEN_OV7620] = {
1830c0d06caSMauro Carvalho Chehab .has_brightness = 1,
1840c0d06caSMauro Carvalho Chehab .has_contrast = 1,
1850c0d06caSMauro Carvalho Chehab .has_sat = 1,
1860c0d06caSMauro Carvalho Chehab .has_autobright = 1,
1870c0d06caSMauro Carvalho Chehab .has_freq = 1,
1880c0d06caSMauro Carvalho Chehab },
1890c0d06caSMauro Carvalho Chehab [SEN_OV7620AE] = {
1900c0d06caSMauro Carvalho Chehab .has_brightness = 1,
1910c0d06caSMauro Carvalho Chehab .has_contrast = 1,
1920c0d06caSMauro Carvalho Chehab .has_sat = 1,
1930c0d06caSMauro Carvalho Chehab .has_autobright = 1,
1940c0d06caSMauro Carvalho Chehab .has_freq = 1,
1950c0d06caSMauro Carvalho Chehab },
1960c0d06caSMauro Carvalho Chehab [SEN_OV7640] = {
1970c0d06caSMauro Carvalho Chehab .has_brightness = 1,
1980c0d06caSMauro Carvalho Chehab .has_sat = 1,
1990c0d06caSMauro Carvalho Chehab .has_freq = 1,
2000c0d06caSMauro Carvalho Chehab },
2010c0d06caSMauro Carvalho Chehab [SEN_OV7648] = {
2020c0d06caSMauro Carvalho Chehab .has_brightness = 1,
2030c0d06caSMauro Carvalho Chehab .has_sat = 1,
2040c0d06caSMauro Carvalho Chehab .has_freq = 1,
2050c0d06caSMauro Carvalho Chehab },
2060c0d06caSMauro Carvalho Chehab [SEN_OV7660] = {
2070c0d06caSMauro Carvalho Chehab .has_brightness = 1,
2080c0d06caSMauro Carvalho Chehab .has_contrast = 1,
2090c0d06caSMauro Carvalho Chehab .has_sat = 1,
2100c0d06caSMauro Carvalho Chehab .has_hvflip = 1,
2110c0d06caSMauro Carvalho Chehab .has_freq = 1,
2120c0d06caSMauro Carvalho Chehab },
2130c0d06caSMauro Carvalho Chehab [SEN_OV7670] = {
2140c0d06caSMauro Carvalho Chehab .has_brightness = 1,
2150c0d06caSMauro Carvalho Chehab .has_contrast = 1,
2160c0d06caSMauro Carvalho Chehab .has_hvflip = 1,
2170c0d06caSMauro Carvalho Chehab .has_freq = 1,
2180c0d06caSMauro Carvalho Chehab },
2190c0d06caSMauro Carvalho Chehab [SEN_OV76BE] = {
2200c0d06caSMauro Carvalho Chehab .has_brightness = 1,
2210c0d06caSMauro Carvalho Chehab .has_contrast = 1,
2220c0d06caSMauro Carvalho Chehab .has_sat = 1,
2230c0d06caSMauro Carvalho Chehab .has_autobright = 1,
2240c0d06caSMauro Carvalho Chehab .has_freq = 1,
2250c0d06caSMauro Carvalho Chehab },
2260c0d06caSMauro Carvalho Chehab [SEN_OV8610] = {
2270c0d06caSMauro Carvalho Chehab .has_brightness = 1,
2280c0d06caSMauro Carvalho Chehab .has_contrast = 1,
2290c0d06caSMauro Carvalho Chehab .has_sat = 1,
2300c0d06caSMauro Carvalho Chehab .has_autobright = 1,
2310c0d06caSMauro Carvalho Chehab },
2320c0d06caSMauro Carvalho Chehab [SEN_OV9600] = {
2330c0d06caSMauro Carvalho Chehab .has_exposure = 1,
2340c0d06caSMauro Carvalho Chehab .has_autogain = 1,
2350c0d06caSMauro Carvalho Chehab },
2360c0d06caSMauro Carvalho Chehab };
2370c0d06caSMauro Carvalho Chehab
2380c0d06caSMauro Carvalho Chehab static const struct v4l2_pix_format ov519_vga_mode[] = {
2390c0d06caSMauro Carvalho Chehab {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
2400c0d06caSMauro Carvalho Chehab .bytesperline = 320,
2410c0d06caSMauro Carvalho Chehab .sizeimage = 320 * 240 * 3 / 8 + 590,
2420c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_JPEG,
2430c0d06caSMauro Carvalho Chehab .priv = 1},
2440c0d06caSMauro Carvalho Chehab {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
2450c0d06caSMauro Carvalho Chehab .bytesperline = 640,
2460c0d06caSMauro Carvalho Chehab .sizeimage = 640 * 480 * 3 / 8 + 590,
2470c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_JPEG,
2480c0d06caSMauro Carvalho Chehab .priv = 0},
2490c0d06caSMauro Carvalho Chehab };
2500c0d06caSMauro Carvalho Chehab static const struct v4l2_pix_format ov519_sif_mode[] = {
2510c0d06caSMauro Carvalho Chehab {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
2520c0d06caSMauro Carvalho Chehab .bytesperline = 160,
2530c0d06caSMauro Carvalho Chehab .sizeimage = 160 * 120 * 3 / 8 + 590,
2540c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_JPEG,
2550c0d06caSMauro Carvalho Chehab .priv = 3},
2560c0d06caSMauro Carvalho Chehab {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
2570c0d06caSMauro Carvalho Chehab .bytesperline = 176,
2580c0d06caSMauro Carvalho Chehab .sizeimage = 176 * 144 * 3 / 8 + 590,
2590c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_JPEG,
2600c0d06caSMauro Carvalho Chehab .priv = 1},
2610c0d06caSMauro Carvalho Chehab {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
2620c0d06caSMauro Carvalho Chehab .bytesperline = 320,
2630c0d06caSMauro Carvalho Chehab .sizeimage = 320 * 240 * 3 / 8 + 590,
2640c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_JPEG,
2650c0d06caSMauro Carvalho Chehab .priv = 2},
2660c0d06caSMauro Carvalho Chehab {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
2670c0d06caSMauro Carvalho Chehab .bytesperline = 352,
2680c0d06caSMauro Carvalho Chehab .sizeimage = 352 * 288 * 3 / 8 + 590,
2690c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_JPEG,
2700c0d06caSMauro Carvalho Chehab .priv = 0},
2710c0d06caSMauro Carvalho Chehab };
2720c0d06caSMauro Carvalho Chehab
2730c0d06caSMauro Carvalho Chehab /* Note some of the sizeimage values for the ov511 / ov518 may seem
2740c0d06caSMauro Carvalho Chehab larger then necessary, however they need to be this big as the ov511 /
2750c0d06caSMauro Carvalho Chehab ov518 always fills the entire isoc frame, using 0 padding bytes when
2760c0d06caSMauro Carvalho Chehab it doesn't have any data. So with low framerates the amount of data
2770c0d06caSMauro Carvalho Chehab transferred can become quite large (libv4l will remove all the 0 padding
2780c0d06caSMauro Carvalho Chehab in userspace). */
2790c0d06caSMauro Carvalho Chehab static const struct v4l2_pix_format ov518_vga_mode[] = {
2800c0d06caSMauro Carvalho Chehab {320, 240, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE,
2810c0d06caSMauro Carvalho Chehab .bytesperline = 320,
2820c0d06caSMauro Carvalho Chehab .sizeimage = 320 * 240 * 3,
2830c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_JPEG,
2840c0d06caSMauro Carvalho Chehab .priv = 1},
2850c0d06caSMauro Carvalho Chehab {640, 480, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE,
2860c0d06caSMauro Carvalho Chehab .bytesperline = 640,
2870c0d06caSMauro Carvalho Chehab .sizeimage = 640 * 480 * 2,
2880c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_JPEG,
2890c0d06caSMauro Carvalho Chehab .priv = 0},
2900c0d06caSMauro Carvalho Chehab };
2910c0d06caSMauro Carvalho Chehab static const struct v4l2_pix_format ov518_sif_mode[] = {
2920c0d06caSMauro Carvalho Chehab {160, 120, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE,
2930c0d06caSMauro Carvalho Chehab .bytesperline = 160,
2940c0d06caSMauro Carvalho Chehab .sizeimage = 70000,
2950c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_JPEG,
2960c0d06caSMauro Carvalho Chehab .priv = 3},
2970c0d06caSMauro Carvalho Chehab {176, 144, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE,
2980c0d06caSMauro Carvalho Chehab .bytesperline = 176,
2990c0d06caSMauro Carvalho Chehab .sizeimage = 70000,
3000c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_JPEG,
3010c0d06caSMauro Carvalho Chehab .priv = 1},
3020c0d06caSMauro Carvalho Chehab {320, 240, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE,
3030c0d06caSMauro Carvalho Chehab .bytesperline = 320,
3040c0d06caSMauro Carvalho Chehab .sizeimage = 320 * 240 * 3,
3050c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_JPEG,
3060c0d06caSMauro Carvalho Chehab .priv = 2},
3070c0d06caSMauro Carvalho Chehab {352, 288, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE,
3080c0d06caSMauro Carvalho Chehab .bytesperline = 352,
3090c0d06caSMauro Carvalho Chehab .sizeimage = 352 * 288 * 3,
3100c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_JPEG,
3110c0d06caSMauro Carvalho Chehab .priv = 0},
3120c0d06caSMauro Carvalho Chehab };
3130c0d06caSMauro Carvalho Chehab
3140c0d06caSMauro Carvalho Chehab static const struct v4l2_pix_format ov511_vga_mode[] = {
3150c0d06caSMauro Carvalho Chehab {320, 240, V4L2_PIX_FMT_OV511, V4L2_FIELD_NONE,
3160c0d06caSMauro Carvalho Chehab .bytesperline = 320,
3170c0d06caSMauro Carvalho Chehab .sizeimage = 320 * 240 * 3,
3180c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_JPEG,
3190c0d06caSMauro Carvalho Chehab .priv = 1},
3200c0d06caSMauro Carvalho Chehab {640, 480, V4L2_PIX_FMT_OV511, V4L2_FIELD_NONE,
3210c0d06caSMauro Carvalho Chehab .bytesperline = 640,
3220c0d06caSMauro Carvalho Chehab .sizeimage = 640 * 480 * 2,
3230c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_JPEG,
3240c0d06caSMauro Carvalho Chehab .priv = 0},
3250c0d06caSMauro Carvalho Chehab };
3260c0d06caSMauro Carvalho Chehab static const struct v4l2_pix_format ov511_sif_mode[] = {
3270c0d06caSMauro Carvalho Chehab {160, 120, V4L2_PIX_FMT_OV511, V4L2_FIELD_NONE,
3280c0d06caSMauro Carvalho Chehab .bytesperline = 160,
3290c0d06caSMauro Carvalho Chehab .sizeimage = 70000,
3300c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_JPEG,
3310c0d06caSMauro Carvalho Chehab .priv = 3},
3320c0d06caSMauro Carvalho Chehab {176, 144, V4L2_PIX_FMT_OV511, V4L2_FIELD_NONE,
3330c0d06caSMauro Carvalho Chehab .bytesperline = 176,
3340c0d06caSMauro Carvalho Chehab .sizeimage = 70000,
3350c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_JPEG,
3360c0d06caSMauro Carvalho Chehab .priv = 1},
3370c0d06caSMauro Carvalho Chehab {320, 240, V4L2_PIX_FMT_OV511, V4L2_FIELD_NONE,
3380c0d06caSMauro Carvalho Chehab .bytesperline = 320,
3390c0d06caSMauro Carvalho Chehab .sizeimage = 320 * 240 * 3,
3400c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_JPEG,
3410c0d06caSMauro Carvalho Chehab .priv = 2},
3420c0d06caSMauro Carvalho Chehab {352, 288, V4L2_PIX_FMT_OV511, V4L2_FIELD_NONE,
3430c0d06caSMauro Carvalho Chehab .bytesperline = 352,
3440c0d06caSMauro Carvalho Chehab .sizeimage = 352 * 288 * 3,
3450c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_JPEG,
3460c0d06caSMauro Carvalho Chehab .priv = 0},
3470c0d06caSMauro Carvalho Chehab };
3480c0d06caSMauro Carvalho Chehab
3490c0d06caSMauro Carvalho Chehab static const struct v4l2_pix_format ovfx2_ov2610_mode[] = {
3500c0d06caSMauro Carvalho Chehab {800, 600, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
3510c0d06caSMauro Carvalho Chehab .bytesperline = 800,
3520c0d06caSMauro Carvalho Chehab .sizeimage = 800 * 600,
3530c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_SRGB,
3540c0d06caSMauro Carvalho Chehab .priv = 1},
3550c0d06caSMauro Carvalho Chehab {1600, 1200, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
3560c0d06caSMauro Carvalho Chehab .bytesperline = 1600,
3570c0d06caSMauro Carvalho Chehab .sizeimage = 1600 * 1200,
3580c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_SRGB},
3590c0d06caSMauro Carvalho Chehab };
3600c0d06caSMauro Carvalho Chehab static const struct v4l2_pix_format ovfx2_ov3610_mode[] = {
3610c0d06caSMauro Carvalho Chehab {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
3620c0d06caSMauro Carvalho Chehab .bytesperline = 640,
3630c0d06caSMauro Carvalho Chehab .sizeimage = 640 * 480,
3640c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_SRGB,
3650c0d06caSMauro Carvalho Chehab .priv = 1},
3660c0d06caSMauro Carvalho Chehab {800, 600, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
3670c0d06caSMauro Carvalho Chehab .bytesperline = 800,
3680c0d06caSMauro Carvalho Chehab .sizeimage = 800 * 600,
3690c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_SRGB,
3700c0d06caSMauro Carvalho Chehab .priv = 1},
3710c0d06caSMauro Carvalho Chehab {1024, 768, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
3720c0d06caSMauro Carvalho Chehab .bytesperline = 1024,
3730c0d06caSMauro Carvalho Chehab .sizeimage = 1024 * 768,
3740c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_SRGB,
3750c0d06caSMauro Carvalho Chehab .priv = 1},
3760c0d06caSMauro Carvalho Chehab {1600, 1200, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
3770c0d06caSMauro Carvalho Chehab .bytesperline = 1600,
3780c0d06caSMauro Carvalho Chehab .sizeimage = 1600 * 1200,
3790c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_SRGB,
3800c0d06caSMauro Carvalho Chehab .priv = 0},
3810c0d06caSMauro Carvalho Chehab {2048, 1536, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
3820c0d06caSMauro Carvalho Chehab .bytesperline = 2048,
3830c0d06caSMauro Carvalho Chehab .sizeimage = 2048 * 1536,
3840c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_SRGB,
3850c0d06caSMauro Carvalho Chehab .priv = 0},
3860c0d06caSMauro Carvalho Chehab };
3870c0d06caSMauro Carvalho Chehab static const struct v4l2_pix_format ovfx2_ov9600_mode[] = {
3880c0d06caSMauro Carvalho Chehab {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
3890c0d06caSMauro Carvalho Chehab .bytesperline = 640,
3900c0d06caSMauro Carvalho Chehab .sizeimage = 640 * 480,
3910c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_SRGB,
3920c0d06caSMauro Carvalho Chehab .priv = 1},
3930c0d06caSMauro Carvalho Chehab {1280, 1024, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
3940c0d06caSMauro Carvalho Chehab .bytesperline = 1280,
3950c0d06caSMauro Carvalho Chehab .sizeimage = 1280 * 1024,
3960c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_SRGB},
3970c0d06caSMauro Carvalho Chehab };
3980c0d06caSMauro Carvalho Chehab
3990c0d06caSMauro Carvalho Chehab /* Registers common to OV511 / OV518 */
4000c0d06caSMauro Carvalho Chehab #define R51x_FIFO_PSIZE 0x30 /* 2 bytes wide w/ OV518(+) */
4010c0d06caSMauro Carvalho Chehab #define R51x_SYS_RESET 0x50
4020c0d06caSMauro Carvalho Chehab /* Reset type flags */
4030c0d06caSMauro Carvalho Chehab #define OV511_RESET_OMNICE 0x08
4040c0d06caSMauro Carvalho Chehab #define R51x_SYS_INIT 0x53
4050c0d06caSMauro Carvalho Chehab #define R51x_SYS_SNAP 0x52
4060c0d06caSMauro Carvalho Chehab #define R51x_SYS_CUST_ID 0x5f
4070c0d06caSMauro Carvalho Chehab #define R51x_COMP_LUT_BEGIN 0x80
4080c0d06caSMauro Carvalho Chehab
4090c0d06caSMauro Carvalho Chehab /* OV511 Camera interface register numbers */
4100c0d06caSMauro Carvalho Chehab #define R511_CAM_DELAY 0x10
4110c0d06caSMauro Carvalho Chehab #define R511_CAM_EDGE 0x11
4120c0d06caSMauro Carvalho Chehab #define R511_CAM_PXCNT 0x12
4130c0d06caSMauro Carvalho Chehab #define R511_CAM_LNCNT 0x13
4140c0d06caSMauro Carvalho Chehab #define R511_CAM_PXDIV 0x14
4150c0d06caSMauro Carvalho Chehab #define R511_CAM_LNDIV 0x15
4160c0d06caSMauro Carvalho Chehab #define R511_CAM_UV_EN 0x16
4170c0d06caSMauro Carvalho Chehab #define R511_CAM_LINE_MODE 0x17
4180c0d06caSMauro Carvalho Chehab #define R511_CAM_OPTS 0x18
4190c0d06caSMauro Carvalho Chehab
4200c0d06caSMauro Carvalho Chehab #define R511_SNAP_FRAME 0x19
4210c0d06caSMauro Carvalho Chehab #define R511_SNAP_PXCNT 0x1a
4220c0d06caSMauro Carvalho Chehab #define R511_SNAP_LNCNT 0x1b
4230c0d06caSMauro Carvalho Chehab #define R511_SNAP_PXDIV 0x1c
4240c0d06caSMauro Carvalho Chehab #define R511_SNAP_LNDIV 0x1d
4250c0d06caSMauro Carvalho Chehab #define R511_SNAP_UV_EN 0x1e
4260c0d06caSMauro Carvalho Chehab #define R511_SNAP_OPTS 0x1f
4270c0d06caSMauro Carvalho Chehab
4280c0d06caSMauro Carvalho Chehab #define R511_DRAM_FLOW_CTL 0x20
4290c0d06caSMauro Carvalho Chehab #define R511_FIFO_OPTS 0x31
4300c0d06caSMauro Carvalho Chehab #define R511_I2C_CTL 0x40
4310c0d06caSMauro Carvalho Chehab #define R511_SYS_LED_CTL 0x55 /* OV511+ only */
4320c0d06caSMauro Carvalho Chehab #define R511_COMP_EN 0x78
4330c0d06caSMauro Carvalho Chehab #define R511_COMP_LUT_EN 0x79
4340c0d06caSMauro Carvalho Chehab
4350c0d06caSMauro Carvalho Chehab /* OV518 Camera interface register numbers */
4360c0d06caSMauro Carvalho Chehab #define R518_GPIO_OUT 0x56 /* OV518(+) only */
4370c0d06caSMauro Carvalho Chehab #define R518_GPIO_CTL 0x57 /* OV518(+) only */
4380c0d06caSMauro Carvalho Chehab
4390c0d06caSMauro Carvalho Chehab /* OV519 Camera interface register numbers */
4400c0d06caSMauro Carvalho Chehab #define OV519_R10_H_SIZE 0x10
4410c0d06caSMauro Carvalho Chehab #define OV519_R11_V_SIZE 0x11
4420c0d06caSMauro Carvalho Chehab #define OV519_R12_X_OFFSETL 0x12
4430c0d06caSMauro Carvalho Chehab #define OV519_R13_X_OFFSETH 0x13
4440c0d06caSMauro Carvalho Chehab #define OV519_R14_Y_OFFSETL 0x14
4450c0d06caSMauro Carvalho Chehab #define OV519_R15_Y_OFFSETH 0x15
4460c0d06caSMauro Carvalho Chehab #define OV519_R16_DIVIDER 0x16
4470c0d06caSMauro Carvalho Chehab #define OV519_R20_DFR 0x20
4480c0d06caSMauro Carvalho Chehab #define OV519_R25_FORMAT 0x25
4490c0d06caSMauro Carvalho Chehab
4500c0d06caSMauro Carvalho Chehab /* OV519 System Controller register numbers */
4510c0d06caSMauro Carvalho Chehab #define OV519_R51_RESET1 0x51
4520c0d06caSMauro Carvalho Chehab #define OV519_R54_EN_CLK1 0x54
4530c0d06caSMauro Carvalho Chehab #define OV519_R57_SNAPSHOT 0x57
4540c0d06caSMauro Carvalho Chehab
4550c0d06caSMauro Carvalho Chehab #define OV519_GPIO_DATA_OUT0 0x71
4560c0d06caSMauro Carvalho Chehab #define OV519_GPIO_IO_CTRL0 0x72
4570c0d06caSMauro Carvalho Chehab
4580c0d06caSMauro Carvalho Chehab /*#define OV511_ENDPOINT_ADDRESS 1 * Isoc endpoint number */
4590c0d06caSMauro Carvalho Chehab
4600c0d06caSMauro Carvalho Chehab /*
4610c0d06caSMauro Carvalho Chehab * The FX2 chip does not give us a zero length read at end of frame.
4620c0d06caSMauro Carvalho Chehab * It does, however, give a short read at the end of a frame, if
4630c0d06caSMauro Carvalho Chehab * necessary, rather than run two frames together.
4640c0d06caSMauro Carvalho Chehab *
4650c0d06caSMauro Carvalho Chehab * By choosing the right bulk transfer size, we are guaranteed to always
4660c0d06caSMauro Carvalho Chehab * get a short read for the last read of each frame. Frame sizes are
4670c0d06caSMauro Carvalho Chehab * always a composite number (width * height, or a multiple) so if we
4680c0d06caSMauro Carvalho Chehab * choose a prime number, we are guaranteed that the last read of a
4690c0d06caSMauro Carvalho Chehab * frame will be short.
4700c0d06caSMauro Carvalho Chehab *
4710c0d06caSMauro Carvalho Chehab * But it isn't that easy: the 2.6 kernel requires a multiple of 4KB,
4720c0d06caSMauro Carvalho Chehab * otherwise EOVERFLOW "babbling" errors occur. I have not been able
4730c0d06caSMauro Carvalho Chehab * to figure out why. [PMiller]
4740c0d06caSMauro Carvalho Chehab *
4750c0d06caSMauro Carvalho Chehab * The constant (13 * 4096) is the largest "prime enough" number less than 64KB.
4760c0d06caSMauro Carvalho Chehab *
4770c0d06caSMauro Carvalho Chehab * It isn't enough to know the number of bytes per frame, in case we
4780c0d06caSMauro Carvalho Chehab * have data dropouts or buffer overruns (even though the FX2 double
4790c0d06caSMauro Carvalho Chehab * buffers, there are some pretty strict real time constraints for
4800c0d06caSMauro Carvalho Chehab * isochronous transfer for larger frame sizes).
4810c0d06caSMauro Carvalho Chehab */
4820c0d06caSMauro Carvalho Chehab /*jfm: this value does not work for 800x600 - see isoc_init */
4830c0d06caSMauro Carvalho Chehab #define OVFX2_BULK_SIZE (13 * 4096)
4840c0d06caSMauro Carvalho Chehab
4850c0d06caSMauro Carvalho Chehab /* I2C registers */
4860c0d06caSMauro Carvalho Chehab #define R51x_I2C_W_SID 0x41
4870c0d06caSMauro Carvalho Chehab #define R51x_I2C_SADDR_3 0x42
4880c0d06caSMauro Carvalho Chehab #define R51x_I2C_SADDR_2 0x43
4890c0d06caSMauro Carvalho Chehab #define R51x_I2C_R_SID 0x44
4900c0d06caSMauro Carvalho Chehab #define R51x_I2C_DATA 0x45
4910c0d06caSMauro Carvalho Chehab #define R518_I2C_CTL 0x47 /* OV518(+) only */
4920c0d06caSMauro Carvalho Chehab #define OVFX2_I2C_ADDR 0x00
4930c0d06caSMauro Carvalho Chehab
4940c0d06caSMauro Carvalho Chehab /* I2C ADDRESSES */
4950c0d06caSMauro Carvalho Chehab #define OV7xx0_SID 0x42
4960c0d06caSMauro Carvalho Chehab #define OV_HIRES_SID 0x60 /* OV9xxx / OV2xxx / OV3xxx */
4970c0d06caSMauro Carvalho Chehab #define OV8xx0_SID 0xa0
4980c0d06caSMauro Carvalho Chehab #define OV6xx0_SID 0xc0
4990c0d06caSMauro Carvalho Chehab
5000c0d06caSMauro Carvalho Chehab /* OV7610 registers */
5010c0d06caSMauro Carvalho Chehab #define OV7610_REG_GAIN 0x00 /* gain setting (5:0) */
5020c0d06caSMauro Carvalho Chehab #define OV7610_REG_BLUE 0x01 /* blue channel balance */
5030c0d06caSMauro Carvalho Chehab #define OV7610_REG_RED 0x02 /* red channel balance */
5040c0d06caSMauro Carvalho Chehab #define OV7610_REG_SAT 0x03 /* saturation */
5050c0d06caSMauro Carvalho Chehab #define OV8610_REG_HUE 0x04 /* 04 reserved */
5060c0d06caSMauro Carvalho Chehab #define OV7610_REG_CNT 0x05 /* Y contrast */
5070c0d06caSMauro Carvalho Chehab #define OV7610_REG_BRT 0x06 /* Y brightness */
5080c0d06caSMauro Carvalho Chehab #define OV7610_REG_COM_C 0x14 /* misc common regs */
5090c0d06caSMauro Carvalho Chehab #define OV7610_REG_ID_HIGH 0x1c /* manufacturer ID MSB */
5100c0d06caSMauro Carvalho Chehab #define OV7610_REG_ID_LOW 0x1d /* manufacturer ID LSB */
5110c0d06caSMauro Carvalho Chehab #define OV7610_REG_COM_I 0x29 /* misc settings */
5120c0d06caSMauro Carvalho Chehab
5130c0d06caSMauro Carvalho Chehab /* OV7660 and OV7670 registers */
5140c0d06caSMauro Carvalho Chehab #define OV7670_R00_GAIN 0x00 /* Gain lower 8 bits (rest in vref) */
5150c0d06caSMauro Carvalho Chehab #define OV7670_R01_BLUE 0x01 /* blue gain */
5160c0d06caSMauro Carvalho Chehab #define OV7670_R02_RED 0x02 /* red gain */
5170c0d06caSMauro Carvalho Chehab #define OV7670_R03_VREF 0x03 /* Pieces of GAIN, VSTART, VSTOP */
5180c0d06caSMauro Carvalho Chehab #define OV7670_R04_COM1 0x04 /* Control 1 */
5190c0d06caSMauro Carvalho Chehab /*#define OV7670_R07_AECHH 0x07 * AEC MS 5 bits */
5200c0d06caSMauro Carvalho Chehab #define OV7670_R0C_COM3 0x0c /* Control 3 */
5210c0d06caSMauro Carvalho Chehab #define OV7670_R0D_COM4 0x0d /* Control 4 */
5220c0d06caSMauro Carvalho Chehab #define OV7670_R0E_COM5 0x0e /* All "reserved" */
5230c0d06caSMauro Carvalho Chehab #define OV7670_R0F_COM6 0x0f /* Control 6 */
5240c0d06caSMauro Carvalho Chehab #define OV7670_R10_AECH 0x10 /* More bits of AEC value */
5250c0d06caSMauro Carvalho Chehab #define OV7670_R11_CLKRC 0x11 /* Clock control */
5260c0d06caSMauro Carvalho Chehab #define OV7670_R12_COM7 0x12 /* Control 7 */
5270c0d06caSMauro Carvalho Chehab #define OV7670_COM7_FMT_VGA 0x00
5280c0d06caSMauro Carvalho Chehab /*#define OV7670_COM7_YUV 0x00 * YUV */
5290c0d06caSMauro Carvalho Chehab #define OV7670_COM7_FMT_QVGA 0x10 /* QVGA format */
5300c0d06caSMauro Carvalho Chehab #define OV7670_COM7_FMT_MASK 0x38
5310c0d06caSMauro Carvalho Chehab #define OV7670_COM7_RESET 0x80 /* Register reset */
5320c0d06caSMauro Carvalho Chehab #define OV7670_R13_COM8 0x13 /* Control 8 */
5330c0d06caSMauro Carvalho Chehab #define OV7670_COM8_AEC 0x01 /* Auto exposure enable */
5340c0d06caSMauro Carvalho Chehab #define OV7670_COM8_AWB 0x02 /* White balance enable */
5350c0d06caSMauro Carvalho Chehab #define OV7670_COM8_AGC 0x04 /* Auto gain enable */
5360c0d06caSMauro Carvalho Chehab #define OV7670_COM8_BFILT 0x20 /* Band filter enable */
5370c0d06caSMauro Carvalho Chehab #define OV7670_COM8_AECSTEP 0x40 /* Unlimited AEC step size */
5380c0d06caSMauro Carvalho Chehab #define OV7670_COM8_FASTAEC 0x80 /* Enable fast AGC/AEC */
5390c0d06caSMauro Carvalho Chehab #define OV7670_R14_COM9 0x14 /* Control 9 - gain ceiling */
5400c0d06caSMauro Carvalho Chehab #define OV7670_R15_COM10 0x15 /* Control 10 */
5410c0d06caSMauro Carvalho Chehab #define OV7670_R17_HSTART 0x17 /* Horiz start high bits */
5420c0d06caSMauro Carvalho Chehab #define OV7670_R18_HSTOP 0x18 /* Horiz stop high bits */
5430c0d06caSMauro Carvalho Chehab #define OV7670_R19_VSTART 0x19 /* Vert start high bits */
5440c0d06caSMauro Carvalho Chehab #define OV7670_R1A_VSTOP 0x1a /* Vert stop high bits */
5450c0d06caSMauro Carvalho Chehab #define OV7670_R1E_MVFP 0x1e /* Mirror / vflip */
5460c0d06caSMauro Carvalho Chehab #define OV7670_MVFP_VFLIP 0x10 /* vertical flip */
5470c0d06caSMauro Carvalho Chehab #define OV7670_MVFP_MIRROR 0x20 /* Mirror image */
5480c0d06caSMauro Carvalho Chehab #define OV7670_R24_AEW 0x24 /* AGC upper limit */
5490c0d06caSMauro Carvalho Chehab #define OV7670_R25_AEB 0x25 /* AGC lower limit */
5500c0d06caSMauro Carvalho Chehab #define OV7670_R26_VPT 0x26 /* AGC/AEC fast mode op region */
5510c0d06caSMauro Carvalho Chehab #define OV7670_R32_HREF 0x32 /* HREF pieces */
5520c0d06caSMauro Carvalho Chehab #define OV7670_R3A_TSLB 0x3a /* lots of stuff */
5530c0d06caSMauro Carvalho Chehab #define OV7670_R3B_COM11 0x3b /* Control 11 */
5540c0d06caSMauro Carvalho Chehab #define OV7670_COM11_EXP 0x02
5550c0d06caSMauro Carvalho Chehab #define OV7670_COM11_HZAUTO 0x10 /* Auto detect 50/60 Hz */
5560c0d06caSMauro Carvalho Chehab #define OV7670_R3C_COM12 0x3c /* Control 12 */
5570c0d06caSMauro Carvalho Chehab #define OV7670_R3D_COM13 0x3d /* Control 13 */
5580c0d06caSMauro Carvalho Chehab #define OV7670_COM13_GAMMA 0x80 /* Gamma enable */
5590c0d06caSMauro Carvalho Chehab #define OV7670_COM13_UVSAT 0x40 /* UV saturation auto adjustment */
5600c0d06caSMauro Carvalho Chehab #define OV7670_R3E_COM14 0x3e /* Control 14 */
5610c0d06caSMauro Carvalho Chehab #define OV7670_R3F_EDGE 0x3f /* Edge enhancement factor */
5620c0d06caSMauro Carvalho Chehab #define OV7670_R40_COM15 0x40 /* Control 15 */
5630c0d06caSMauro Carvalho Chehab /*#define OV7670_COM15_R00FF 0xc0 * 00 to FF */
5640c0d06caSMauro Carvalho Chehab #define OV7670_R41_COM16 0x41 /* Control 16 */
5650c0d06caSMauro Carvalho Chehab #define OV7670_COM16_AWBGAIN 0x08 /* AWB gain enable */
5660c0d06caSMauro Carvalho Chehab /* end of ov7660 common registers */
5670c0d06caSMauro Carvalho Chehab #define OV7670_R55_BRIGHT 0x55 /* Brightness */
5680c0d06caSMauro Carvalho Chehab #define OV7670_R56_CONTRAS 0x56 /* Contrast control */
5690c0d06caSMauro Carvalho Chehab #define OV7670_R69_GFIX 0x69 /* Fix gain control */
5700c0d06caSMauro Carvalho Chehab /*#define OV7670_R8C_RGB444 0x8c * RGB 444 control */
5710c0d06caSMauro Carvalho Chehab #define OV7670_R9F_HAECC1 0x9f /* Hist AEC/AGC control 1 */
5720c0d06caSMauro Carvalho Chehab #define OV7670_RA0_HAECC2 0xa0 /* Hist AEC/AGC control 2 */
5730c0d06caSMauro Carvalho Chehab #define OV7670_RA5_BD50MAX 0xa5 /* 50hz banding step limit */
5740c0d06caSMauro Carvalho Chehab #define OV7670_RA6_HAECC3 0xa6 /* Hist AEC/AGC control 3 */
5750c0d06caSMauro Carvalho Chehab #define OV7670_RA7_HAECC4 0xa7 /* Hist AEC/AGC control 4 */
5760c0d06caSMauro Carvalho Chehab #define OV7670_RA8_HAECC5 0xa8 /* Hist AEC/AGC control 5 */
5770c0d06caSMauro Carvalho Chehab #define OV7670_RA9_HAECC6 0xa9 /* Hist AEC/AGC control 6 */
5780c0d06caSMauro Carvalho Chehab #define OV7670_RAA_HAECC7 0xaa /* Hist AEC/AGC control 7 */
5790c0d06caSMauro Carvalho Chehab #define OV7670_RAB_BD60MAX 0xab /* 60hz banding step limit */
5800c0d06caSMauro Carvalho Chehab
5810c0d06caSMauro Carvalho Chehab struct ov_regvals {
5820c0d06caSMauro Carvalho Chehab u8 reg;
5830c0d06caSMauro Carvalho Chehab u8 val;
5840c0d06caSMauro Carvalho Chehab };
5850c0d06caSMauro Carvalho Chehab struct ov_i2c_regvals {
5860c0d06caSMauro Carvalho Chehab u8 reg;
5870c0d06caSMauro Carvalho Chehab u8 val;
5880c0d06caSMauro Carvalho Chehab };
5890c0d06caSMauro Carvalho Chehab
5900c0d06caSMauro Carvalho Chehab /* Settings for OV2610 camera chip */
5910c0d06caSMauro Carvalho Chehab static const struct ov_i2c_regvals norm_2610[] = {
5920c0d06caSMauro Carvalho Chehab { 0x12, 0x80 }, /* reset */
5930c0d06caSMauro Carvalho Chehab };
5940c0d06caSMauro Carvalho Chehab
5950c0d06caSMauro Carvalho Chehab static const struct ov_i2c_regvals norm_2610ae[] = {
5960c0d06caSMauro Carvalho Chehab {0x12, 0x80}, /* reset */
5970c0d06caSMauro Carvalho Chehab {0x13, 0xcd},
5980c0d06caSMauro Carvalho Chehab {0x09, 0x01},
5990c0d06caSMauro Carvalho Chehab {0x0d, 0x00},
6000c0d06caSMauro Carvalho Chehab {0x11, 0x80},
6010c0d06caSMauro Carvalho Chehab {0x12, 0x20}, /* 1600x1200 */
6020c0d06caSMauro Carvalho Chehab {0x33, 0x0c},
6030c0d06caSMauro Carvalho Chehab {0x35, 0x90},
6040c0d06caSMauro Carvalho Chehab {0x36, 0x37},
6050c0d06caSMauro Carvalho Chehab /* ms-win traces */
6060c0d06caSMauro Carvalho Chehab {0x11, 0x83}, /* clock / 3 ? */
6070c0d06caSMauro Carvalho Chehab {0x2d, 0x00}, /* 60 Hz filter */
6080c0d06caSMauro Carvalho Chehab {0x24, 0xb0}, /* normal colors */
6090c0d06caSMauro Carvalho Chehab {0x25, 0x90},
6100c0d06caSMauro Carvalho Chehab {0x10, 0x43},
6110c0d06caSMauro Carvalho Chehab };
6120c0d06caSMauro Carvalho Chehab
6130c0d06caSMauro Carvalho Chehab static const struct ov_i2c_regvals norm_3620b[] = {
6140c0d06caSMauro Carvalho Chehab /*
6150c0d06caSMauro Carvalho Chehab * From the datasheet: "Note that after writing to register COMH
6160c0d06caSMauro Carvalho Chehab * (0x12) to change the sensor mode, registers related to the
617*df5ce27dSMauro Carvalho Chehab * sensor's cropping window will be reset back to their default
6180c0d06caSMauro Carvalho Chehab * values."
6190c0d06caSMauro Carvalho Chehab *
6200c0d06caSMauro Carvalho Chehab * "wait 4096 external clock ... to make sure the sensor is
6210c0d06caSMauro Carvalho Chehab * stable and ready to access registers" i.e. 160us at 24MHz
6220c0d06caSMauro Carvalho Chehab */
6230c0d06caSMauro Carvalho Chehab { 0x12, 0x80 }, /* COMH reset */
6240c0d06caSMauro Carvalho Chehab { 0x12, 0x00 }, /* QXGA, master */
6250c0d06caSMauro Carvalho Chehab
6260c0d06caSMauro Carvalho Chehab /*
6270c0d06caSMauro Carvalho Chehab * 11 CLKRC "Clock Rate Control"
6280c0d06caSMauro Carvalho Chehab * [7] internal frequency doublers: on
6290c0d06caSMauro Carvalho Chehab * [6] video port mode: master
6300c0d06caSMauro Carvalho Chehab * [5:0] clock divider: 1
6310c0d06caSMauro Carvalho Chehab */
6320c0d06caSMauro Carvalho Chehab { 0x11, 0x80 },
6330c0d06caSMauro Carvalho Chehab
6340c0d06caSMauro Carvalho Chehab /*
6350c0d06caSMauro Carvalho Chehab * 13 COMI "Common Control I"
6360c0d06caSMauro Carvalho Chehab * = 192 (0xC0) 11000000
6370c0d06caSMauro Carvalho Chehab * COMI[7] "AEC speed selection"
6380c0d06caSMauro Carvalho Chehab * = 1 (0x01) 1....... "Faster AEC correction"
6390c0d06caSMauro Carvalho Chehab * COMI[6] "AEC speed step selection"
6400c0d06caSMauro Carvalho Chehab * = 1 (0x01) .1...... "Big steps, fast"
6410c0d06caSMauro Carvalho Chehab * COMI[5] "Banding filter on off"
6420c0d06caSMauro Carvalho Chehab * = 0 (0x00) ..0..... "Off"
6430c0d06caSMauro Carvalho Chehab * COMI[4] "Banding filter option"
6440c0d06caSMauro Carvalho Chehab * = 0 (0x00) ...0.... "Main clock is 48 MHz and
6450c0d06caSMauro Carvalho Chehab * the PLL is ON"
6460c0d06caSMauro Carvalho Chehab * COMI[3] "Reserved"
6470c0d06caSMauro Carvalho Chehab * = 0 (0x00) ....0...
6480c0d06caSMauro Carvalho Chehab * COMI[2] "AGC auto manual control selection"
6490c0d06caSMauro Carvalho Chehab * = 0 (0x00) .....0.. "Manual"
6500c0d06caSMauro Carvalho Chehab * COMI[1] "AWB auto manual control selection"
6510c0d06caSMauro Carvalho Chehab * = 0 (0x00) ......0. "Manual"
6520c0d06caSMauro Carvalho Chehab * COMI[0] "Exposure control"
6530c0d06caSMauro Carvalho Chehab * = 0 (0x00) .......0 "Manual"
6540c0d06caSMauro Carvalho Chehab */
6550c0d06caSMauro Carvalho Chehab { 0x13, 0xc0 },
6560c0d06caSMauro Carvalho Chehab
6570c0d06caSMauro Carvalho Chehab /*
6580c0d06caSMauro Carvalho Chehab * 09 COMC "Common Control C"
6590c0d06caSMauro Carvalho Chehab * = 8 (0x08) 00001000
6600c0d06caSMauro Carvalho Chehab * COMC[7:5] "Reserved"
6610c0d06caSMauro Carvalho Chehab * = 0 (0x00) 000.....
6620c0d06caSMauro Carvalho Chehab * COMC[4] "Sleep Mode Enable"
6630c0d06caSMauro Carvalho Chehab * = 0 (0x00) ...0.... "Normal mode"
6640c0d06caSMauro Carvalho Chehab * COMC[3:2] "Sensor sampling reset timing selection"
6650c0d06caSMauro Carvalho Chehab * = 2 (0x02) ....10.. "Longer reset time"
6660c0d06caSMauro Carvalho Chehab * COMC[1:0] "Output drive current select"
6670c0d06caSMauro Carvalho Chehab * = 0 (0x00) ......00 "Weakest"
6680c0d06caSMauro Carvalho Chehab */
6690c0d06caSMauro Carvalho Chehab { 0x09, 0x08 },
6700c0d06caSMauro Carvalho Chehab
6710c0d06caSMauro Carvalho Chehab /*
6720c0d06caSMauro Carvalho Chehab * 0C COMD "Common Control D"
6730c0d06caSMauro Carvalho Chehab * = 8 (0x08) 00001000
6740c0d06caSMauro Carvalho Chehab * COMD[7] "Reserved"
6750c0d06caSMauro Carvalho Chehab * = 0 (0x00) 0.......
6760c0d06caSMauro Carvalho Chehab * COMD[6] "Swap MSB and LSB at the output port"
6770c0d06caSMauro Carvalho Chehab * = 0 (0x00) .0...... "False"
6780c0d06caSMauro Carvalho Chehab * COMD[5:3] "Reserved"
6790c0d06caSMauro Carvalho Chehab * = 1 (0x01) ..001...
6800c0d06caSMauro Carvalho Chehab * COMD[2] "Output Average On Off"
6810c0d06caSMauro Carvalho Chehab * = 0 (0x00) .....0.. "Output Normal"
6820c0d06caSMauro Carvalho Chehab * COMD[1] "Sensor precharge voltage selection"
6830c0d06caSMauro Carvalho Chehab * = 0 (0x00) ......0. "Selects internal
6840c0d06caSMauro Carvalho Chehab * reference precharge
6850c0d06caSMauro Carvalho Chehab * voltage"
6860c0d06caSMauro Carvalho Chehab * COMD[0] "Snapshot option"
6870c0d06caSMauro Carvalho Chehab * = 0 (0x00) .......0 "Enable live video output
6880c0d06caSMauro Carvalho Chehab * after snapshot sequence"
6890c0d06caSMauro Carvalho Chehab */
6900c0d06caSMauro Carvalho Chehab { 0x0c, 0x08 },
6910c0d06caSMauro Carvalho Chehab
6920c0d06caSMauro Carvalho Chehab /*
6930c0d06caSMauro Carvalho Chehab * 0D COME "Common Control E"
6940c0d06caSMauro Carvalho Chehab * = 161 (0xA1) 10100001
6950c0d06caSMauro Carvalho Chehab * COME[7] "Output average option"
6960c0d06caSMauro Carvalho Chehab * = 1 (0x01) 1....... "Output average of 4 pixels"
6970c0d06caSMauro Carvalho Chehab * COME[6] "Anti-blooming control"
6980c0d06caSMauro Carvalho Chehab * = 0 (0x00) .0...... "Off"
6990c0d06caSMauro Carvalho Chehab * COME[5:3] "Reserved"
7000c0d06caSMauro Carvalho Chehab * = 4 (0x04) ..100...
7010c0d06caSMauro Carvalho Chehab * COME[2] "Clock output power down pin status"
7020c0d06caSMauro Carvalho Chehab * = 0 (0x00) .....0.. "Tri-state data output pin
7030c0d06caSMauro Carvalho Chehab * on power down"
7040c0d06caSMauro Carvalho Chehab * COME[1] "Data output pin status selection at power down"
7050c0d06caSMauro Carvalho Chehab * = 0 (0x00) ......0. "Tri-state VSYNC, PCLK,
7060c0d06caSMauro Carvalho Chehab * HREF, and CHSYNC pins on
7070c0d06caSMauro Carvalho Chehab * power down"
7080c0d06caSMauro Carvalho Chehab * COME[0] "Auto zero circuit select"
7090c0d06caSMauro Carvalho Chehab * = 1 (0x01) .......1 "On"
7100c0d06caSMauro Carvalho Chehab */
7110c0d06caSMauro Carvalho Chehab { 0x0d, 0xa1 },
7120c0d06caSMauro Carvalho Chehab
7130c0d06caSMauro Carvalho Chehab /*
7140c0d06caSMauro Carvalho Chehab * 0E COMF "Common Control F"
7150c0d06caSMauro Carvalho Chehab * = 112 (0x70) 01110000
7160c0d06caSMauro Carvalho Chehab * COMF[7] "System clock selection"
7170c0d06caSMauro Carvalho Chehab * = 0 (0x00) 0....... "Use 24 MHz system clock"
7180c0d06caSMauro Carvalho Chehab * COMF[6:4] "Reserved"
7190c0d06caSMauro Carvalho Chehab * = 7 (0x07) .111....
7200c0d06caSMauro Carvalho Chehab * COMF[3] "Manual auto negative offset canceling selection"
7210c0d06caSMauro Carvalho Chehab * = 0 (0x00) ....0... "Auto detect negative
7220c0d06caSMauro Carvalho Chehab * offset and cancel it"
7230c0d06caSMauro Carvalho Chehab * COMF[2:0] "Reserved"
7240c0d06caSMauro Carvalho Chehab * = 0 (0x00) .....000
7250c0d06caSMauro Carvalho Chehab */
7260c0d06caSMauro Carvalho Chehab { 0x0e, 0x70 },
7270c0d06caSMauro Carvalho Chehab
7280c0d06caSMauro Carvalho Chehab /*
7290c0d06caSMauro Carvalho Chehab * 0F COMG "Common Control G"
7300c0d06caSMauro Carvalho Chehab * = 66 (0x42) 01000010
7310c0d06caSMauro Carvalho Chehab * COMG[7] "Optical black output selection"
7320c0d06caSMauro Carvalho Chehab * = 0 (0x00) 0....... "Disable"
7330c0d06caSMauro Carvalho Chehab * COMG[6] "Black level calibrate selection"
7340c0d06caSMauro Carvalho Chehab * = 1 (0x01) .1...... "Use optical black pixels
7350c0d06caSMauro Carvalho Chehab * to calibrate"
7360c0d06caSMauro Carvalho Chehab * COMG[5:4] "Reserved"
7370c0d06caSMauro Carvalho Chehab * = 0 (0x00) ..00....
7380c0d06caSMauro Carvalho Chehab * COMG[3] "Channel offset adjustment"
7390c0d06caSMauro Carvalho Chehab * = 0 (0x00) ....0... "Disable offset adjustment"
7400c0d06caSMauro Carvalho Chehab * COMG[2] "ADC black level calibration option"
7410c0d06caSMauro Carvalho Chehab * = 0 (0x00) .....0.. "Use B/G line and G/R
7420c0d06caSMauro Carvalho Chehab * line to calibrate each
7430c0d06caSMauro Carvalho Chehab * channel's black level"
7440c0d06caSMauro Carvalho Chehab * COMG[1] "Reserved"
7450c0d06caSMauro Carvalho Chehab * = 1 (0x01) ......1.
7460c0d06caSMauro Carvalho Chehab * COMG[0] "ADC black level calibration enable"
7470c0d06caSMauro Carvalho Chehab * = 0 (0x00) .......0 "Disable"
7480c0d06caSMauro Carvalho Chehab */
7490c0d06caSMauro Carvalho Chehab { 0x0f, 0x42 },
7500c0d06caSMauro Carvalho Chehab
7510c0d06caSMauro Carvalho Chehab /*
7520c0d06caSMauro Carvalho Chehab * 14 COMJ "Common Control J"
7530c0d06caSMauro Carvalho Chehab * = 198 (0xC6) 11000110
7540c0d06caSMauro Carvalho Chehab * COMJ[7:6] "AGC gain ceiling"
7550c0d06caSMauro Carvalho Chehab * = 3 (0x03) 11...... "8x"
7560c0d06caSMauro Carvalho Chehab * COMJ[5:4] "Reserved"
7570c0d06caSMauro Carvalho Chehab * = 0 (0x00) ..00....
7580c0d06caSMauro Carvalho Chehab * COMJ[3] "Auto banding filter"
7590c0d06caSMauro Carvalho Chehab * = 0 (0x00) ....0... "Banding filter is always
7600c0d06caSMauro Carvalho Chehab * on off depending on
7610c0d06caSMauro Carvalho Chehab * COMI[5] setting"
7620c0d06caSMauro Carvalho Chehab * COMJ[2] "VSYNC drop option"
7630c0d06caSMauro Carvalho Chehab * = 1 (0x01) .....1.. "SYNC is dropped if frame
7640c0d06caSMauro Carvalho Chehab * data is dropped"
7650c0d06caSMauro Carvalho Chehab * COMJ[1] "Frame data drop"
7660c0d06caSMauro Carvalho Chehab * = 1 (0x01) ......1. "Drop frame data if
7670c0d06caSMauro Carvalho Chehab * exposure is not within
7680c0d06caSMauro Carvalho Chehab * tolerance. In AEC mode,
7690c0d06caSMauro Carvalho Chehab * data is normally dropped
7700c0d06caSMauro Carvalho Chehab * when data is out of
7710c0d06caSMauro Carvalho Chehab * range."
7720c0d06caSMauro Carvalho Chehab * COMJ[0] "Reserved"
7730c0d06caSMauro Carvalho Chehab * = 0 (0x00) .......0
7740c0d06caSMauro Carvalho Chehab */
7750c0d06caSMauro Carvalho Chehab { 0x14, 0xc6 },
7760c0d06caSMauro Carvalho Chehab
7770c0d06caSMauro Carvalho Chehab /*
7780c0d06caSMauro Carvalho Chehab * 15 COMK "Common Control K"
7790c0d06caSMauro Carvalho Chehab * = 2 (0x02) 00000010
7800c0d06caSMauro Carvalho Chehab * COMK[7] "CHSYNC pin output swap"
7810c0d06caSMauro Carvalho Chehab * = 0 (0x00) 0....... "CHSYNC"
7820c0d06caSMauro Carvalho Chehab * COMK[6] "HREF pin output swap"
7830c0d06caSMauro Carvalho Chehab * = 0 (0x00) .0...... "HREF"
7840c0d06caSMauro Carvalho Chehab * COMK[5] "PCLK output selection"
7850c0d06caSMauro Carvalho Chehab * = 0 (0x00) ..0..... "PCLK always output"
7860c0d06caSMauro Carvalho Chehab * COMK[4] "PCLK edge selection"
7870c0d06caSMauro Carvalho Chehab * = 0 (0x00) ...0.... "Data valid on falling edge"
7880c0d06caSMauro Carvalho Chehab * COMK[3] "HREF output polarity"
7890c0d06caSMauro Carvalho Chehab * = 0 (0x00) ....0... "positive"
7900c0d06caSMauro Carvalho Chehab * COMK[2] "Reserved"
7910c0d06caSMauro Carvalho Chehab * = 0 (0x00) .....0..
7920c0d06caSMauro Carvalho Chehab * COMK[1] "VSYNC polarity"
7930c0d06caSMauro Carvalho Chehab * = 1 (0x01) ......1. "negative"
7940c0d06caSMauro Carvalho Chehab * COMK[0] "HSYNC polarity"
7950c0d06caSMauro Carvalho Chehab * = 0 (0x00) .......0 "positive"
7960c0d06caSMauro Carvalho Chehab */
7970c0d06caSMauro Carvalho Chehab { 0x15, 0x02 },
7980c0d06caSMauro Carvalho Chehab
7990c0d06caSMauro Carvalho Chehab /*
8000c0d06caSMauro Carvalho Chehab * 33 CHLF "Current Control"
8010c0d06caSMauro Carvalho Chehab * = 9 (0x09) 00001001
8020c0d06caSMauro Carvalho Chehab * CHLF[7:6] "Sensor current control"
8030c0d06caSMauro Carvalho Chehab * = 0 (0x00) 00......
8040c0d06caSMauro Carvalho Chehab * CHLF[5] "Sensor current range control"
8050c0d06caSMauro Carvalho Chehab * = 0 (0x00) ..0..... "normal range"
8060c0d06caSMauro Carvalho Chehab * CHLF[4] "Sensor current"
8070c0d06caSMauro Carvalho Chehab * = 0 (0x00) ...0.... "normal current"
8080c0d06caSMauro Carvalho Chehab * CHLF[3] "Sensor buffer current control"
8090c0d06caSMauro Carvalho Chehab * = 1 (0x01) ....1... "half current"
8100c0d06caSMauro Carvalho Chehab * CHLF[2] "Column buffer current control"
8110c0d06caSMauro Carvalho Chehab * = 0 (0x00) .....0.. "normal current"
8120c0d06caSMauro Carvalho Chehab * CHLF[1] "Analog DSP current control"
8130c0d06caSMauro Carvalho Chehab * = 0 (0x00) ......0. "normal current"
8140c0d06caSMauro Carvalho Chehab * CHLF[1] "ADC current control"
8150c0d06caSMauro Carvalho Chehab * = 0 (0x00) ......0. "normal current"
8160c0d06caSMauro Carvalho Chehab */
8170c0d06caSMauro Carvalho Chehab { 0x33, 0x09 },
8180c0d06caSMauro Carvalho Chehab
8190c0d06caSMauro Carvalho Chehab /*
8200c0d06caSMauro Carvalho Chehab * 34 VBLM "Blooming Control"
8210c0d06caSMauro Carvalho Chehab * = 80 (0x50) 01010000
8220c0d06caSMauro Carvalho Chehab * VBLM[7] "Hard soft reset switch"
8230c0d06caSMauro Carvalho Chehab * = 0 (0x00) 0....... "Hard reset"
8240c0d06caSMauro Carvalho Chehab * VBLM[6:4] "Blooming voltage selection"
8250c0d06caSMauro Carvalho Chehab * = 5 (0x05) .101....
8260c0d06caSMauro Carvalho Chehab * VBLM[3:0] "Sensor current control"
8270c0d06caSMauro Carvalho Chehab * = 0 (0x00) ....0000
8280c0d06caSMauro Carvalho Chehab */
8290c0d06caSMauro Carvalho Chehab { 0x34, 0x50 },
8300c0d06caSMauro Carvalho Chehab
8310c0d06caSMauro Carvalho Chehab /*
8320c0d06caSMauro Carvalho Chehab * 36 VCHG "Sensor Precharge Voltage Control"
8330c0d06caSMauro Carvalho Chehab * = 0 (0x00) 00000000
8340c0d06caSMauro Carvalho Chehab * VCHG[7] "Reserved"
8350c0d06caSMauro Carvalho Chehab * = 0 (0x00) 0.......
8360c0d06caSMauro Carvalho Chehab * VCHG[6:4] "Sensor precharge voltage control"
8370c0d06caSMauro Carvalho Chehab * = 0 (0x00) .000....
8380c0d06caSMauro Carvalho Chehab * VCHG[3:0] "Sensor array common reference"
8390c0d06caSMauro Carvalho Chehab * = 0 (0x00) ....0000
8400c0d06caSMauro Carvalho Chehab */
8410c0d06caSMauro Carvalho Chehab { 0x36, 0x00 },
8420c0d06caSMauro Carvalho Chehab
8430c0d06caSMauro Carvalho Chehab /*
8440c0d06caSMauro Carvalho Chehab * 37 ADC "ADC Reference Control"
8450c0d06caSMauro Carvalho Chehab * = 4 (0x04) 00000100
8460c0d06caSMauro Carvalho Chehab * ADC[7:4] "Reserved"
8470c0d06caSMauro Carvalho Chehab * = 0 (0x00) 0000....
8480c0d06caSMauro Carvalho Chehab * ADC[3] "ADC input signal range"
8490c0d06caSMauro Carvalho Chehab * = 0 (0x00) ....0... "Input signal 1.0x"
8500c0d06caSMauro Carvalho Chehab * ADC[2:0] "ADC range control"
8510c0d06caSMauro Carvalho Chehab * = 4 (0x04) .....100
8520c0d06caSMauro Carvalho Chehab */
8530c0d06caSMauro Carvalho Chehab { 0x37, 0x04 },
8540c0d06caSMauro Carvalho Chehab
8550c0d06caSMauro Carvalho Chehab /*
8560c0d06caSMauro Carvalho Chehab * 38 ACOM "Analog Common Ground"
8570c0d06caSMauro Carvalho Chehab * = 82 (0x52) 01010010
8580c0d06caSMauro Carvalho Chehab * ACOM[7] "Analog gain control"
8590c0d06caSMauro Carvalho Chehab * = 0 (0x00) 0....... "Gain 1x"
8600c0d06caSMauro Carvalho Chehab * ACOM[6] "Analog black level calibration"
8610c0d06caSMauro Carvalho Chehab * = 1 (0x01) .1...... "On"
8620c0d06caSMauro Carvalho Chehab * ACOM[5:0] "Reserved"
8630c0d06caSMauro Carvalho Chehab * = 18 (0x12) ..010010
8640c0d06caSMauro Carvalho Chehab */
8650c0d06caSMauro Carvalho Chehab { 0x38, 0x52 },
8660c0d06caSMauro Carvalho Chehab
8670c0d06caSMauro Carvalho Chehab /*
8680c0d06caSMauro Carvalho Chehab * 3A FREFA "Internal Reference Adjustment"
8690c0d06caSMauro Carvalho Chehab * = 0 (0x00) 00000000
8700c0d06caSMauro Carvalho Chehab * FREFA[7:0] "Range"
8710c0d06caSMauro Carvalho Chehab * = 0 (0x00) 00000000
8720c0d06caSMauro Carvalho Chehab */
8730c0d06caSMauro Carvalho Chehab { 0x3a, 0x00 },
8740c0d06caSMauro Carvalho Chehab
8750c0d06caSMauro Carvalho Chehab /*
8760c0d06caSMauro Carvalho Chehab * 3C FVOPT "Internal Reference Adjustment"
8770c0d06caSMauro Carvalho Chehab * = 31 (0x1F) 00011111
8780c0d06caSMauro Carvalho Chehab * FVOPT[7:0] "Range"
8790c0d06caSMauro Carvalho Chehab * = 31 (0x1F) 00011111
8800c0d06caSMauro Carvalho Chehab */
8810c0d06caSMauro Carvalho Chehab { 0x3c, 0x1f },
8820c0d06caSMauro Carvalho Chehab
8830c0d06caSMauro Carvalho Chehab /*
8840c0d06caSMauro Carvalho Chehab * 44 Undocumented = 0 (0x00) 00000000
8850c0d06caSMauro Carvalho Chehab * 44[7:0] "It's a secret"
8860c0d06caSMauro Carvalho Chehab * = 0 (0x00) 00000000
8870c0d06caSMauro Carvalho Chehab */
8880c0d06caSMauro Carvalho Chehab { 0x44, 0x00 },
8890c0d06caSMauro Carvalho Chehab
8900c0d06caSMauro Carvalho Chehab /*
8910c0d06caSMauro Carvalho Chehab * 40 Undocumented = 0 (0x00) 00000000
8920c0d06caSMauro Carvalho Chehab * 40[7:0] "It's a secret"
8930c0d06caSMauro Carvalho Chehab * = 0 (0x00) 00000000
8940c0d06caSMauro Carvalho Chehab */
8950c0d06caSMauro Carvalho Chehab { 0x40, 0x00 },
8960c0d06caSMauro Carvalho Chehab
8970c0d06caSMauro Carvalho Chehab /*
8980c0d06caSMauro Carvalho Chehab * 41 Undocumented = 0 (0x00) 00000000
8990c0d06caSMauro Carvalho Chehab * 41[7:0] "It's a secret"
9000c0d06caSMauro Carvalho Chehab * = 0 (0x00) 00000000
9010c0d06caSMauro Carvalho Chehab */
9020c0d06caSMauro Carvalho Chehab { 0x41, 0x00 },
9030c0d06caSMauro Carvalho Chehab
9040c0d06caSMauro Carvalho Chehab /*
9050c0d06caSMauro Carvalho Chehab * 42 Undocumented = 0 (0x00) 00000000
9060c0d06caSMauro Carvalho Chehab * 42[7:0] "It's a secret"
9070c0d06caSMauro Carvalho Chehab * = 0 (0x00) 00000000
9080c0d06caSMauro Carvalho Chehab */
9090c0d06caSMauro Carvalho Chehab { 0x42, 0x00 },
9100c0d06caSMauro Carvalho Chehab
9110c0d06caSMauro Carvalho Chehab /*
9120c0d06caSMauro Carvalho Chehab * 43 Undocumented = 0 (0x00) 00000000
9130c0d06caSMauro Carvalho Chehab * 43[7:0] "It's a secret"
9140c0d06caSMauro Carvalho Chehab * = 0 (0x00) 00000000
9150c0d06caSMauro Carvalho Chehab */
9160c0d06caSMauro Carvalho Chehab { 0x43, 0x00 },
9170c0d06caSMauro Carvalho Chehab
9180c0d06caSMauro Carvalho Chehab /*
9190c0d06caSMauro Carvalho Chehab * 45 Undocumented = 128 (0x80) 10000000
9200c0d06caSMauro Carvalho Chehab * 45[7:0] "It's a secret"
9210c0d06caSMauro Carvalho Chehab * = 128 (0x80) 10000000
9220c0d06caSMauro Carvalho Chehab */
9230c0d06caSMauro Carvalho Chehab { 0x45, 0x80 },
9240c0d06caSMauro Carvalho Chehab
9250c0d06caSMauro Carvalho Chehab /*
9260c0d06caSMauro Carvalho Chehab * 48 Undocumented = 192 (0xC0) 11000000
9270c0d06caSMauro Carvalho Chehab * 48[7:0] "It's a secret"
9280c0d06caSMauro Carvalho Chehab * = 192 (0xC0) 11000000
9290c0d06caSMauro Carvalho Chehab */
9300c0d06caSMauro Carvalho Chehab { 0x48, 0xc0 },
9310c0d06caSMauro Carvalho Chehab
9320c0d06caSMauro Carvalho Chehab /*
9330c0d06caSMauro Carvalho Chehab * 49 Undocumented = 25 (0x19) 00011001
9340c0d06caSMauro Carvalho Chehab * 49[7:0] "It's a secret"
9350c0d06caSMauro Carvalho Chehab * = 25 (0x19) 00011001
9360c0d06caSMauro Carvalho Chehab */
9370c0d06caSMauro Carvalho Chehab { 0x49, 0x19 },
9380c0d06caSMauro Carvalho Chehab
9390c0d06caSMauro Carvalho Chehab /*
9400c0d06caSMauro Carvalho Chehab * 4B Undocumented = 128 (0x80) 10000000
9410c0d06caSMauro Carvalho Chehab * 4B[7:0] "It's a secret"
9420c0d06caSMauro Carvalho Chehab * = 128 (0x80) 10000000
9430c0d06caSMauro Carvalho Chehab */
9440c0d06caSMauro Carvalho Chehab { 0x4b, 0x80 },
9450c0d06caSMauro Carvalho Chehab
9460c0d06caSMauro Carvalho Chehab /*
9470c0d06caSMauro Carvalho Chehab * 4D Undocumented = 196 (0xC4) 11000100
9480c0d06caSMauro Carvalho Chehab * 4D[7:0] "It's a secret"
9490c0d06caSMauro Carvalho Chehab * = 196 (0xC4) 11000100
9500c0d06caSMauro Carvalho Chehab */
9510c0d06caSMauro Carvalho Chehab { 0x4d, 0xc4 },
9520c0d06caSMauro Carvalho Chehab
9530c0d06caSMauro Carvalho Chehab /*
9540c0d06caSMauro Carvalho Chehab * 35 VREF "Reference Voltage Control"
9550c0d06caSMauro Carvalho Chehab * = 76 (0x4c) 01001100
9560c0d06caSMauro Carvalho Chehab * VREF[7:5] "Column high reference control"
9570c0d06caSMauro Carvalho Chehab * = 2 (0x02) 010..... "higher voltage"
9580c0d06caSMauro Carvalho Chehab * VREF[4:2] "Column low reference control"
9590c0d06caSMauro Carvalho Chehab * = 3 (0x03) ...011.. "Highest voltage"
9600c0d06caSMauro Carvalho Chehab * VREF[1:0] "Reserved"
9610c0d06caSMauro Carvalho Chehab * = 0 (0x00) ......00
9620c0d06caSMauro Carvalho Chehab */
9630c0d06caSMauro Carvalho Chehab { 0x35, 0x4c },
9640c0d06caSMauro Carvalho Chehab
9650c0d06caSMauro Carvalho Chehab /*
9660c0d06caSMauro Carvalho Chehab * 3D Undocumented = 0 (0x00) 00000000
9670c0d06caSMauro Carvalho Chehab * 3D[7:0] "It's a secret"
9680c0d06caSMauro Carvalho Chehab * = 0 (0x00) 00000000
9690c0d06caSMauro Carvalho Chehab */
9700c0d06caSMauro Carvalho Chehab { 0x3d, 0x00 },
9710c0d06caSMauro Carvalho Chehab
9720c0d06caSMauro Carvalho Chehab /*
9730c0d06caSMauro Carvalho Chehab * 3E Undocumented = 0 (0x00) 00000000
9740c0d06caSMauro Carvalho Chehab * 3E[7:0] "It's a secret"
9750c0d06caSMauro Carvalho Chehab * = 0 (0x00) 00000000
9760c0d06caSMauro Carvalho Chehab */
9770c0d06caSMauro Carvalho Chehab { 0x3e, 0x00 },
9780c0d06caSMauro Carvalho Chehab
9790c0d06caSMauro Carvalho Chehab /*
9800c0d06caSMauro Carvalho Chehab * 3B FREFB "Internal Reference Adjustment"
9810c0d06caSMauro Carvalho Chehab * = 24 (0x18) 00011000
9820c0d06caSMauro Carvalho Chehab * FREFB[7:0] "Range"
9830c0d06caSMauro Carvalho Chehab * = 24 (0x18) 00011000
9840c0d06caSMauro Carvalho Chehab */
9850c0d06caSMauro Carvalho Chehab { 0x3b, 0x18 },
9860c0d06caSMauro Carvalho Chehab
9870c0d06caSMauro Carvalho Chehab /*
9880c0d06caSMauro Carvalho Chehab * 33 CHLF "Current Control"
9890c0d06caSMauro Carvalho Chehab * = 25 (0x19) 00011001
9900c0d06caSMauro Carvalho Chehab * CHLF[7:6] "Sensor current control"
9910c0d06caSMauro Carvalho Chehab * = 0 (0x00) 00......
9920c0d06caSMauro Carvalho Chehab * CHLF[5] "Sensor current range control"
9930c0d06caSMauro Carvalho Chehab * = 0 (0x00) ..0..... "normal range"
9940c0d06caSMauro Carvalho Chehab * CHLF[4] "Sensor current"
9950c0d06caSMauro Carvalho Chehab * = 1 (0x01) ...1.... "double current"
9960c0d06caSMauro Carvalho Chehab * CHLF[3] "Sensor buffer current control"
9970c0d06caSMauro Carvalho Chehab * = 1 (0x01) ....1... "half current"
9980c0d06caSMauro Carvalho Chehab * CHLF[2] "Column buffer current control"
9990c0d06caSMauro Carvalho Chehab * = 0 (0x00) .....0.. "normal current"
10000c0d06caSMauro Carvalho Chehab * CHLF[1] "Analog DSP current control"
10010c0d06caSMauro Carvalho Chehab * = 0 (0x00) ......0. "normal current"
10020c0d06caSMauro Carvalho Chehab * CHLF[1] "ADC current control"
10030c0d06caSMauro Carvalho Chehab * = 0 (0x00) ......0. "normal current"
10040c0d06caSMauro Carvalho Chehab */
10050c0d06caSMauro Carvalho Chehab { 0x33, 0x19 },
10060c0d06caSMauro Carvalho Chehab
10070c0d06caSMauro Carvalho Chehab /*
10080c0d06caSMauro Carvalho Chehab * 34 VBLM "Blooming Control"
10090c0d06caSMauro Carvalho Chehab * = 90 (0x5A) 01011010
10100c0d06caSMauro Carvalho Chehab * VBLM[7] "Hard soft reset switch"
10110c0d06caSMauro Carvalho Chehab * = 0 (0x00) 0....... "Hard reset"
10120c0d06caSMauro Carvalho Chehab * VBLM[6:4] "Blooming voltage selection"
10130c0d06caSMauro Carvalho Chehab * = 5 (0x05) .101....
10140c0d06caSMauro Carvalho Chehab * VBLM[3:0] "Sensor current control"
10150c0d06caSMauro Carvalho Chehab * = 10 (0x0A) ....1010
10160c0d06caSMauro Carvalho Chehab */
10170c0d06caSMauro Carvalho Chehab { 0x34, 0x5a },
10180c0d06caSMauro Carvalho Chehab
10190c0d06caSMauro Carvalho Chehab /*
10200c0d06caSMauro Carvalho Chehab * 3B FREFB "Internal Reference Adjustment"
10210c0d06caSMauro Carvalho Chehab * = 0 (0x00) 00000000
10220c0d06caSMauro Carvalho Chehab * FREFB[7:0] "Range"
10230c0d06caSMauro Carvalho Chehab * = 0 (0x00) 00000000
10240c0d06caSMauro Carvalho Chehab */
10250c0d06caSMauro Carvalho Chehab { 0x3b, 0x00 },
10260c0d06caSMauro Carvalho Chehab
10270c0d06caSMauro Carvalho Chehab /*
10280c0d06caSMauro Carvalho Chehab * 33 CHLF "Current Control"
10290c0d06caSMauro Carvalho Chehab * = 9 (0x09) 00001001
10300c0d06caSMauro Carvalho Chehab * CHLF[7:6] "Sensor current control"
10310c0d06caSMauro Carvalho Chehab * = 0 (0x00) 00......
10320c0d06caSMauro Carvalho Chehab * CHLF[5] "Sensor current range control"
10330c0d06caSMauro Carvalho Chehab * = 0 (0x00) ..0..... "normal range"
10340c0d06caSMauro Carvalho Chehab * CHLF[4] "Sensor current"
10350c0d06caSMauro Carvalho Chehab * = 0 (0x00) ...0.... "normal current"
10360c0d06caSMauro Carvalho Chehab * CHLF[3] "Sensor buffer current control"
10370c0d06caSMauro Carvalho Chehab * = 1 (0x01) ....1... "half current"
10380c0d06caSMauro Carvalho Chehab * CHLF[2] "Column buffer current control"
10390c0d06caSMauro Carvalho Chehab * = 0 (0x00) .....0.. "normal current"
10400c0d06caSMauro Carvalho Chehab * CHLF[1] "Analog DSP current control"
10410c0d06caSMauro Carvalho Chehab * = 0 (0x00) ......0. "normal current"
10420c0d06caSMauro Carvalho Chehab * CHLF[1] "ADC current control"
10430c0d06caSMauro Carvalho Chehab * = 0 (0x00) ......0. "normal current"
10440c0d06caSMauro Carvalho Chehab */
10450c0d06caSMauro Carvalho Chehab { 0x33, 0x09 },
10460c0d06caSMauro Carvalho Chehab
10470c0d06caSMauro Carvalho Chehab /*
10480c0d06caSMauro Carvalho Chehab * 34 VBLM "Blooming Control"
10490c0d06caSMauro Carvalho Chehab * = 80 (0x50) 01010000
10500c0d06caSMauro Carvalho Chehab * VBLM[7] "Hard soft reset switch"
10510c0d06caSMauro Carvalho Chehab * = 0 (0x00) 0....... "Hard reset"
10520c0d06caSMauro Carvalho Chehab * VBLM[6:4] "Blooming voltage selection"
10530c0d06caSMauro Carvalho Chehab * = 5 (0x05) .101....
10540c0d06caSMauro Carvalho Chehab * VBLM[3:0] "Sensor current control"
10550c0d06caSMauro Carvalho Chehab * = 0 (0x00) ....0000
10560c0d06caSMauro Carvalho Chehab */
10570c0d06caSMauro Carvalho Chehab { 0x34, 0x50 },
10580c0d06caSMauro Carvalho Chehab
10590c0d06caSMauro Carvalho Chehab /*
10600c0d06caSMauro Carvalho Chehab * 12 COMH "Common Control H"
10610c0d06caSMauro Carvalho Chehab * = 64 (0x40) 01000000
10620c0d06caSMauro Carvalho Chehab * COMH[7] "SRST"
10630c0d06caSMauro Carvalho Chehab * = 0 (0x00) 0....... "No-op"
10640c0d06caSMauro Carvalho Chehab * COMH[6:4] "Resolution selection"
10650c0d06caSMauro Carvalho Chehab * = 4 (0x04) .100.... "XGA"
10660c0d06caSMauro Carvalho Chehab * COMH[3] "Master slave selection"
10670c0d06caSMauro Carvalho Chehab * = 0 (0x00) ....0... "Master mode"
10680c0d06caSMauro Carvalho Chehab * COMH[2] "Internal B/R channel option"
10690c0d06caSMauro Carvalho Chehab * = 0 (0x00) .....0.. "B/R use same channel"
10700c0d06caSMauro Carvalho Chehab * COMH[1] "Color bar test pattern"
10710c0d06caSMauro Carvalho Chehab * = 0 (0x00) ......0. "Off"
10720c0d06caSMauro Carvalho Chehab * COMH[0] "Reserved"
10730c0d06caSMauro Carvalho Chehab * = 0 (0x00) .......0
10740c0d06caSMauro Carvalho Chehab */
10750c0d06caSMauro Carvalho Chehab { 0x12, 0x40 },
10760c0d06caSMauro Carvalho Chehab
10770c0d06caSMauro Carvalho Chehab /*
10780c0d06caSMauro Carvalho Chehab * 17 HREFST "Horizontal window start"
10790c0d06caSMauro Carvalho Chehab * = 31 (0x1F) 00011111
10800c0d06caSMauro Carvalho Chehab * HREFST[7:0] "Horizontal window start, 8 MSBs"
10810c0d06caSMauro Carvalho Chehab * = 31 (0x1F) 00011111
10820c0d06caSMauro Carvalho Chehab */
10830c0d06caSMauro Carvalho Chehab { 0x17, 0x1f },
10840c0d06caSMauro Carvalho Chehab
10850c0d06caSMauro Carvalho Chehab /*
10860c0d06caSMauro Carvalho Chehab * 18 HREFEND "Horizontal window end"
10870c0d06caSMauro Carvalho Chehab * = 95 (0x5F) 01011111
10880c0d06caSMauro Carvalho Chehab * HREFEND[7:0] "Horizontal Window End, 8 MSBs"
10890c0d06caSMauro Carvalho Chehab * = 95 (0x5F) 01011111
10900c0d06caSMauro Carvalho Chehab */
10910c0d06caSMauro Carvalho Chehab { 0x18, 0x5f },
10920c0d06caSMauro Carvalho Chehab
10930c0d06caSMauro Carvalho Chehab /*
10940c0d06caSMauro Carvalho Chehab * 19 VSTRT "Vertical window start"
10950c0d06caSMauro Carvalho Chehab * = 0 (0x00) 00000000
10960c0d06caSMauro Carvalho Chehab * VSTRT[7:0] "Vertical Window Start, 8 MSBs"
10970c0d06caSMauro Carvalho Chehab * = 0 (0x00) 00000000
10980c0d06caSMauro Carvalho Chehab */
10990c0d06caSMauro Carvalho Chehab { 0x19, 0x00 },
11000c0d06caSMauro Carvalho Chehab
11010c0d06caSMauro Carvalho Chehab /*
11020c0d06caSMauro Carvalho Chehab * 1A VEND "Vertical window end"
11030c0d06caSMauro Carvalho Chehab * = 96 (0x60) 01100000
11040c0d06caSMauro Carvalho Chehab * VEND[7:0] "Vertical Window End, 8 MSBs"
11050c0d06caSMauro Carvalho Chehab * = 96 (0x60) 01100000
11060c0d06caSMauro Carvalho Chehab */
11070c0d06caSMauro Carvalho Chehab { 0x1a, 0x60 },
11080c0d06caSMauro Carvalho Chehab
11090c0d06caSMauro Carvalho Chehab /*
11100c0d06caSMauro Carvalho Chehab * 32 COMM "Common Control M"
11110c0d06caSMauro Carvalho Chehab * = 18 (0x12) 00010010
11120c0d06caSMauro Carvalho Chehab * COMM[7:6] "Pixel clock divide option"
11130c0d06caSMauro Carvalho Chehab * = 0 (0x00) 00...... "/1"
11140c0d06caSMauro Carvalho Chehab * COMM[5:3] "Horizontal window end position, 3 LSBs"
11150c0d06caSMauro Carvalho Chehab * = 2 (0x02) ..010...
11160c0d06caSMauro Carvalho Chehab * COMM[2:0] "Horizontal window start position, 3 LSBs"
11170c0d06caSMauro Carvalho Chehab * = 2 (0x02) .....010
11180c0d06caSMauro Carvalho Chehab */
11190c0d06caSMauro Carvalho Chehab { 0x32, 0x12 },
11200c0d06caSMauro Carvalho Chehab
11210c0d06caSMauro Carvalho Chehab /*
11220c0d06caSMauro Carvalho Chehab * 03 COMA "Common Control A"
11230c0d06caSMauro Carvalho Chehab * = 74 (0x4A) 01001010
11240c0d06caSMauro Carvalho Chehab * COMA[7:4] "AWB Update Threshold"
11250c0d06caSMauro Carvalho Chehab * = 4 (0x04) 0100....
11260c0d06caSMauro Carvalho Chehab * COMA[3:2] "Vertical window end line control 2 LSBs"
11270c0d06caSMauro Carvalho Chehab * = 2 (0x02) ....10..
11280c0d06caSMauro Carvalho Chehab * COMA[1:0] "Vertical window start line control 2 LSBs"
11290c0d06caSMauro Carvalho Chehab * = 2 (0x02) ......10
11300c0d06caSMauro Carvalho Chehab */
11310c0d06caSMauro Carvalho Chehab { 0x03, 0x4a },
11320c0d06caSMauro Carvalho Chehab
11330c0d06caSMauro Carvalho Chehab /*
11340c0d06caSMauro Carvalho Chehab * 11 CLKRC "Clock Rate Control"
11350c0d06caSMauro Carvalho Chehab * = 128 (0x80) 10000000
11360c0d06caSMauro Carvalho Chehab * CLKRC[7] "Internal frequency doublers on off seclection"
11370c0d06caSMauro Carvalho Chehab * = 1 (0x01) 1....... "On"
11380c0d06caSMauro Carvalho Chehab * CLKRC[6] "Digital video master slave selection"
11390c0d06caSMauro Carvalho Chehab * = 0 (0x00) .0...... "Master mode, sensor
11400c0d06caSMauro Carvalho Chehab * provides PCLK"
11410c0d06caSMauro Carvalho Chehab * CLKRC[5:0] "Clock divider { CLK = PCLK/(1+CLKRC[5:0]) }"
11420c0d06caSMauro Carvalho Chehab * = 0 (0x00) ..000000
11430c0d06caSMauro Carvalho Chehab */
11440c0d06caSMauro Carvalho Chehab { 0x11, 0x80 },
11450c0d06caSMauro Carvalho Chehab
11460c0d06caSMauro Carvalho Chehab /*
11470c0d06caSMauro Carvalho Chehab * 12 COMH "Common Control H"
11480c0d06caSMauro Carvalho Chehab * = 0 (0x00) 00000000
11490c0d06caSMauro Carvalho Chehab * COMH[7] "SRST"
11500c0d06caSMauro Carvalho Chehab * = 0 (0x00) 0....... "No-op"
11510c0d06caSMauro Carvalho Chehab * COMH[6:4] "Resolution selection"
11520c0d06caSMauro Carvalho Chehab * = 0 (0x00) .000.... "QXGA"
11530c0d06caSMauro Carvalho Chehab * COMH[3] "Master slave selection"
11540c0d06caSMauro Carvalho Chehab * = 0 (0x00) ....0... "Master mode"
11550c0d06caSMauro Carvalho Chehab * COMH[2] "Internal B/R channel option"
11560c0d06caSMauro Carvalho Chehab * = 0 (0x00) .....0.. "B/R use same channel"
11570c0d06caSMauro Carvalho Chehab * COMH[1] "Color bar test pattern"
11580c0d06caSMauro Carvalho Chehab * = 0 (0x00) ......0. "Off"
11590c0d06caSMauro Carvalho Chehab * COMH[0] "Reserved"
11600c0d06caSMauro Carvalho Chehab * = 0 (0x00) .......0
11610c0d06caSMauro Carvalho Chehab */
11620c0d06caSMauro Carvalho Chehab { 0x12, 0x00 },
11630c0d06caSMauro Carvalho Chehab
11640c0d06caSMauro Carvalho Chehab /*
11650c0d06caSMauro Carvalho Chehab * 12 COMH "Common Control H"
11660c0d06caSMauro Carvalho Chehab * = 64 (0x40) 01000000
11670c0d06caSMauro Carvalho Chehab * COMH[7] "SRST"
11680c0d06caSMauro Carvalho Chehab * = 0 (0x00) 0....... "No-op"
11690c0d06caSMauro Carvalho Chehab * COMH[6:4] "Resolution selection"
11700c0d06caSMauro Carvalho Chehab * = 4 (0x04) .100.... "XGA"
11710c0d06caSMauro Carvalho Chehab * COMH[3] "Master slave selection"
11720c0d06caSMauro Carvalho Chehab * = 0 (0x00) ....0... "Master mode"
11730c0d06caSMauro Carvalho Chehab * COMH[2] "Internal B/R channel option"
11740c0d06caSMauro Carvalho Chehab * = 0 (0x00) .....0.. "B/R use same channel"
11750c0d06caSMauro Carvalho Chehab * COMH[1] "Color bar test pattern"
11760c0d06caSMauro Carvalho Chehab * = 0 (0x00) ......0. "Off"
11770c0d06caSMauro Carvalho Chehab * COMH[0] "Reserved"
11780c0d06caSMauro Carvalho Chehab * = 0 (0x00) .......0
11790c0d06caSMauro Carvalho Chehab */
11800c0d06caSMauro Carvalho Chehab { 0x12, 0x40 },
11810c0d06caSMauro Carvalho Chehab
11820c0d06caSMauro Carvalho Chehab /*
11830c0d06caSMauro Carvalho Chehab * 17 HREFST "Horizontal window start"
11840c0d06caSMauro Carvalho Chehab * = 31 (0x1F) 00011111
11850c0d06caSMauro Carvalho Chehab * HREFST[7:0] "Horizontal window start, 8 MSBs"
11860c0d06caSMauro Carvalho Chehab * = 31 (0x1F) 00011111
11870c0d06caSMauro Carvalho Chehab */
11880c0d06caSMauro Carvalho Chehab { 0x17, 0x1f },
11890c0d06caSMauro Carvalho Chehab
11900c0d06caSMauro Carvalho Chehab /*
11910c0d06caSMauro Carvalho Chehab * 18 HREFEND "Horizontal window end"
11920c0d06caSMauro Carvalho Chehab * = 95 (0x5F) 01011111
11930c0d06caSMauro Carvalho Chehab * HREFEND[7:0] "Horizontal Window End, 8 MSBs"
11940c0d06caSMauro Carvalho Chehab * = 95 (0x5F) 01011111
11950c0d06caSMauro Carvalho Chehab */
11960c0d06caSMauro Carvalho Chehab { 0x18, 0x5f },
11970c0d06caSMauro Carvalho Chehab
11980c0d06caSMauro Carvalho Chehab /*
11990c0d06caSMauro Carvalho Chehab * 19 VSTRT "Vertical window start"
12000c0d06caSMauro Carvalho Chehab * = 0 (0x00) 00000000
12010c0d06caSMauro Carvalho Chehab * VSTRT[7:0] "Vertical Window Start, 8 MSBs"
12020c0d06caSMauro Carvalho Chehab * = 0 (0x00) 00000000
12030c0d06caSMauro Carvalho Chehab */
12040c0d06caSMauro Carvalho Chehab { 0x19, 0x00 },
12050c0d06caSMauro Carvalho Chehab
12060c0d06caSMauro Carvalho Chehab /*
12070c0d06caSMauro Carvalho Chehab * 1A VEND "Vertical window end"
12080c0d06caSMauro Carvalho Chehab * = 96 (0x60) 01100000
12090c0d06caSMauro Carvalho Chehab * VEND[7:0] "Vertical Window End, 8 MSBs"
12100c0d06caSMauro Carvalho Chehab * = 96 (0x60) 01100000
12110c0d06caSMauro Carvalho Chehab */
12120c0d06caSMauro Carvalho Chehab { 0x1a, 0x60 },
12130c0d06caSMauro Carvalho Chehab
12140c0d06caSMauro Carvalho Chehab /*
12150c0d06caSMauro Carvalho Chehab * 32 COMM "Common Control M"
12160c0d06caSMauro Carvalho Chehab * = 18 (0x12) 00010010
12170c0d06caSMauro Carvalho Chehab * COMM[7:6] "Pixel clock divide option"
12180c0d06caSMauro Carvalho Chehab * = 0 (0x00) 00...... "/1"
12190c0d06caSMauro Carvalho Chehab * COMM[5:3] "Horizontal window end position, 3 LSBs"
12200c0d06caSMauro Carvalho Chehab * = 2 (0x02) ..010...
12210c0d06caSMauro Carvalho Chehab * COMM[2:0] "Horizontal window start position, 3 LSBs"
12220c0d06caSMauro Carvalho Chehab * = 2 (0x02) .....010
12230c0d06caSMauro Carvalho Chehab */
12240c0d06caSMauro Carvalho Chehab { 0x32, 0x12 },
12250c0d06caSMauro Carvalho Chehab
12260c0d06caSMauro Carvalho Chehab /*
12270c0d06caSMauro Carvalho Chehab * 03 COMA "Common Control A"
12280c0d06caSMauro Carvalho Chehab * = 74 (0x4A) 01001010
12290c0d06caSMauro Carvalho Chehab * COMA[7:4] "AWB Update Threshold"
12300c0d06caSMauro Carvalho Chehab * = 4 (0x04) 0100....
12310c0d06caSMauro Carvalho Chehab * COMA[3:2] "Vertical window end line control 2 LSBs"
12320c0d06caSMauro Carvalho Chehab * = 2 (0x02) ....10..
12330c0d06caSMauro Carvalho Chehab * COMA[1:0] "Vertical window start line control 2 LSBs"
12340c0d06caSMauro Carvalho Chehab * = 2 (0x02) ......10
12350c0d06caSMauro Carvalho Chehab */
12360c0d06caSMauro Carvalho Chehab { 0x03, 0x4a },
12370c0d06caSMauro Carvalho Chehab
12380c0d06caSMauro Carvalho Chehab /*
12390c0d06caSMauro Carvalho Chehab * 02 RED "Red Gain Control"
12400c0d06caSMauro Carvalho Chehab * = 175 (0xAF) 10101111
12410c0d06caSMauro Carvalho Chehab * RED[7] "Action"
12420c0d06caSMauro Carvalho Chehab * = 1 (0x01) 1....... "gain = 1/(1+bitrev([6:0]))"
12430c0d06caSMauro Carvalho Chehab * RED[6:0] "Value"
12440c0d06caSMauro Carvalho Chehab * = 47 (0x2F) .0101111
12450c0d06caSMauro Carvalho Chehab */
12460c0d06caSMauro Carvalho Chehab { 0x02, 0xaf },
12470c0d06caSMauro Carvalho Chehab
12480c0d06caSMauro Carvalho Chehab /*
12490c0d06caSMauro Carvalho Chehab * 2D ADDVSL "VSYNC Pulse Width"
12500c0d06caSMauro Carvalho Chehab * = 210 (0xD2) 11010010
12510c0d06caSMauro Carvalho Chehab * ADDVSL[7:0] "VSYNC pulse width, LSB"
12520c0d06caSMauro Carvalho Chehab * = 210 (0xD2) 11010010
12530c0d06caSMauro Carvalho Chehab */
12540c0d06caSMauro Carvalho Chehab { 0x2d, 0xd2 },
12550c0d06caSMauro Carvalho Chehab
12560c0d06caSMauro Carvalho Chehab /*
12570c0d06caSMauro Carvalho Chehab * 00 GAIN = 24 (0x18) 00011000
12580c0d06caSMauro Carvalho Chehab * GAIN[7:6] "Reserved"
12590c0d06caSMauro Carvalho Chehab * = 0 (0x00) 00......
12600c0d06caSMauro Carvalho Chehab * GAIN[5] "Double"
12610c0d06caSMauro Carvalho Chehab * = 0 (0x00) ..0..... "False"
12620c0d06caSMauro Carvalho Chehab * GAIN[4] "Double"
12630c0d06caSMauro Carvalho Chehab * = 1 (0x01) ...1.... "True"
12640c0d06caSMauro Carvalho Chehab * GAIN[3:0] "Range"
12650c0d06caSMauro Carvalho Chehab * = 8 (0x08) ....1000
12660c0d06caSMauro Carvalho Chehab */
12670c0d06caSMauro Carvalho Chehab { 0x00, 0x18 },
12680c0d06caSMauro Carvalho Chehab
12690c0d06caSMauro Carvalho Chehab /*
12700c0d06caSMauro Carvalho Chehab * 01 BLUE "Blue Gain Control"
12710c0d06caSMauro Carvalho Chehab * = 240 (0xF0) 11110000
12720c0d06caSMauro Carvalho Chehab * BLUE[7] "Action"
12730c0d06caSMauro Carvalho Chehab * = 1 (0x01) 1....... "gain = 1/(1+bitrev([6:0]))"
12740c0d06caSMauro Carvalho Chehab * BLUE[6:0] "Value"
12750c0d06caSMauro Carvalho Chehab * = 112 (0x70) .1110000
12760c0d06caSMauro Carvalho Chehab */
12770c0d06caSMauro Carvalho Chehab { 0x01, 0xf0 },
12780c0d06caSMauro Carvalho Chehab
12790c0d06caSMauro Carvalho Chehab /*
12800c0d06caSMauro Carvalho Chehab * 10 AEC "Automatic Exposure Control"
12810c0d06caSMauro Carvalho Chehab * = 10 (0x0A) 00001010
12820c0d06caSMauro Carvalho Chehab * AEC[7:0] "Automatic Exposure Control, 8 MSBs"
12830c0d06caSMauro Carvalho Chehab * = 10 (0x0A) 00001010
12840c0d06caSMauro Carvalho Chehab */
12850c0d06caSMauro Carvalho Chehab { 0x10, 0x0a },
12860c0d06caSMauro Carvalho Chehab
12870c0d06caSMauro Carvalho Chehab { 0xe1, 0x67 },
12880c0d06caSMauro Carvalho Chehab { 0xe3, 0x03 },
12890c0d06caSMauro Carvalho Chehab { 0xe4, 0x26 },
12900c0d06caSMauro Carvalho Chehab { 0xe5, 0x3e },
12910c0d06caSMauro Carvalho Chehab { 0xf8, 0x01 },
12920c0d06caSMauro Carvalho Chehab { 0xff, 0x01 },
12930c0d06caSMauro Carvalho Chehab };
12940c0d06caSMauro Carvalho Chehab
12950c0d06caSMauro Carvalho Chehab static const struct ov_i2c_regvals norm_6x20[] = {
12960c0d06caSMauro Carvalho Chehab { 0x12, 0x80 }, /* reset */
12970c0d06caSMauro Carvalho Chehab { 0x11, 0x01 },
12980c0d06caSMauro Carvalho Chehab { 0x03, 0x60 },
12990c0d06caSMauro Carvalho Chehab { 0x05, 0x7f }, /* For when autoadjust is off */
13000c0d06caSMauro Carvalho Chehab { 0x07, 0xa8 },
13010c0d06caSMauro Carvalho Chehab /* The ratio of 0x0c and 0x0d controls the white point */
13020c0d06caSMauro Carvalho Chehab { 0x0c, 0x24 },
13030c0d06caSMauro Carvalho Chehab { 0x0d, 0x24 },
13040c0d06caSMauro Carvalho Chehab { 0x0f, 0x15 }, /* COMS */
13050c0d06caSMauro Carvalho Chehab { 0x10, 0x75 }, /* AEC Exposure time */
13060c0d06caSMauro Carvalho Chehab { 0x12, 0x24 }, /* Enable AGC */
13070c0d06caSMauro Carvalho Chehab { 0x14, 0x04 },
13080c0d06caSMauro Carvalho Chehab /* 0x16: 0x06 helps frame stability with moving objects */
13090c0d06caSMauro Carvalho Chehab { 0x16, 0x06 },
13100c0d06caSMauro Carvalho Chehab /* { 0x20, 0x30 }, * Aperture correction enable */
13110c0d06caSMauro Carvalho Chehab { 0x26, 0xb2 }, /* BLC enable */
13120c0d06caSMauro Carvalho Chehab /* 0x28: 0x05 Selects RGB format if RGB on */
13130c0d06caSMauro Carvalho Chehab { 0x28, 0x05 },
13140c0d06caSMauro Carvalho Chehab { 0x2a, 0x04 }, /* Disable framerate adjust */
13150c0d06caSMauro Carvalho Chehab /* { 0x2b, 0xac }, * Framerate; Set 2a[7] first */
13160c0d06caSMauro Carvalho Chehab { 0x2d, 0x85 },
13170c0d06caSMauro Carvalho Chehab { 0x33, 0xa0 }, /* Color Processing Parameter */
13180c0d06caSMauro Carvalho Chehab { 0x34, 0xd2 }, /* Max A/D range */
13190c0d06caSMauro Carvalho Chehab { 0x38, 0x8b },
13200c0d06caSMauro Carvalho Chehab { 0x39, 0x40 },
13210c0d06caSMauro Carvalho Chehab
13220c0d06caSMauro Carvalho Chehab { 0x3c, 0x39 }, /* Enable AEC mode changing */
13230c0d06caSMauro Carvalho Chehab { 0x3c, 0x3c }, /* Change AEC mode */
13240c0d06caSMauro Carvalho Chehab { 0x3c, 0x24 }, /* Disable AEC mode changing */
13250c0d06caSMauro Carvalho Chehab
13260c0d06caSMauro Carvalho Chehab { 0x3d, 0x80 },
13270c0d06caSMauro Carvalho Chehab /* These next two registers (0x4a, 0x4b) are undocumented.
13280c0d06caSMauro Carvalho Chehab * They control the color balance */
13290c0d06caSMauro Carvalho Chehab { 0x4a, 0x80 },
13300c0d06caSMauro Carvalho Chehab { 0x4b, 0x80 },
13310c0d06caSMauro Carvalho Chehab { 0x4d, 0xd2 }, /* This reduces noise a bit */
13320c0d06caSMauro Carvalho Chehab { 0x4e, 0xc1 },
13330c0d06caSMauro Carvalho Chehab { 0x4f, 0x04 },
13340c0d06caSMauro Carvalho Chehab /* Do 50-53 have any effect? */
13350c0d06caSMauro Carvalho Chehab /* Toggle 0x12[2] off and on here? */
13360c0d06caSMauro Carvalho Chehab };
13370c0d06caSMauro Carvalho Chehab
13380c0d06caSMauro Carvalho Chehab static const struct ov_i2c_regvals norm_6x30[] = {
13390c0d06caSMauro Carvalho Chehab { 0x12, 0x80 }, /* Reset */
13400c0d06caSMauro Carvalho Chehab { 0x00, 0x1f }, /* Gain */
13410c0d06caSMauro Carvalho Chehab { 0x01, 0x99 }, /* Blue gain */
13420c0d06caSMauro Carvalho Chehab { 0x02, 0x7c }, /* Red gain */
13430c0d06caSMauro Carvalho Chehab { 0x03, 0xc0 }, /* Saturation */
13440c0d06caSMauro Carvalho Chehab { 0x05, 0x0a }, /* Contrast */
13450c0d06caSMauro Carvalho Chehab { 0x06, 0x95 }, /* Brightness */
13460c0d06caSMauro Carvalho Chehab { 0x07, 0x2d }, /* Sharpness */
13470c0d06caSMauro Carvalho Chehab { 0x0c, 0x20 },
13480c0d06caSMauro Carvalho Chehab { 0x0d, 0x20 },
13490c0d06caSMauro Carvalho Chehab { 0x0e, 0xa0 }, /* Was 0x20, bit7 enables a 2x gain which we need */
13500c0d06caSMauro Carvalho Chehab { 0x0f, 0x05 },
13510c0d06caSMauro Carvalho Chehab { 0x10, 0x9a },
13520c0d06caSMauro Carvalho Chehab { 0x11, 0x00 }, /* Pixel clock = fastest */
13530c0d06caSMauro Carvalho Chehab { 0x12, 0x24 }, /* Enable AGC and AWB */
13540c0d06caSMauro Carvalho Chehab { 0x13, 0x21 },
13550c0d06caSMauro Carvalho Chehab { 0x14, 0x80 },
13560c0d06caSMauro Carvalho Chehab { 0x15, 0x01 },
13570c0d06caSMauro Carvalho Chehab { 0x16, 0x03 },
13580c0d06caSMauro Carvalho Chehab { 0x17, 0x38 },
13590c0d06caSMauro Carvalho Chehab { 0x18, 0xea },
13600c0d06caSMauro Carvalho Chehab { 0x19, 0x04 },
13610c0d06caSMauro Carvalho Chehab { 0x1a, 0x93 },
13620c0d06caSMauro Carvalho Chehab { 0x1b, 0x00 },
13630c0d06caSMauro Carvalho Chehab { 0x1e, 0xc4 },
13640c0d06caSMauro Carvalho Chehab { 0x1f, 0x04 },
13650c0d06caSMauro Carvalho Chehab { 0x20, 0x20 },
13660c0d06caSMauro Carvalho Chehab { 0x21, 0x10 },
13670c0d06caSMauro Carvalho Chehab { 0x22, 0x88 },
13680c0d06caSMauro Carvalho Chehab { 0x23, 0xc0 }, /* Crystal circuit power level */
13690c0d06caSMauro Carvalho Chehab { 0x25, 0x9a }, /* Increase AEC black ratio */
13700c0d06caSMauro Carvalho Chehab { 0x26, 0xb2 }, /* BLC enable */
13710c0d06caSMauro Carvalho Chehab { 0x27, 0xa2 },
13720c0d06caSMauro Carvalho Chehab { 0x28, 0x00 },
13730c0d06caSMauro Carvalho Chehab { 0x29, 0x00 },
13740c0d06caSMauro Carvalho Chehab { 0x2a, 0x84 }, /* 60 Hz power */
13750c0d06caSMauro Carvalho Chehab { 0x2b, 0xa8 }, /* 60 Hz power */
13760c0d06caSMauro Carvalho Chehab { 0x2c, 0xa0 },
13770c0d06caSMauro Carvalho Chehab { 0x2d, 0x95 }, /* Enable auto-brightness */
13780c0d06caSMauro Carvalho Chehab { 0x2e, 0x88 },
13790c0d06caSMauro Carvalho Chehab { 0x33, 0x26 },
13800c0d06caSMauro Carvalho Chehab { 0x34, 0x03 },
13810c0d06caSMauro Carvalho Chehab { 0x36, 0x8f },
13820c0d06caSMauro Carvalho Chehab { 0x37, 0x80 },
13830c0d06caSMauro Carvalho Chehab { 0x38, 0x83 },
13840c0d06caSMauro Carvalho Chehab { 0x39, 0x80 },
13850c0d06caSMauro Carvalho Chehab { 0x3a, 0x0f },
13860c0d06caSMauro Carvalho Chehab { 0x3b, 0x3c },
13870c0d06caSMauro Carvalho Chehab { 0x3c, 0x1a },
13880c0d06caSMauro Carvalho Chehab { 0x3d, 0x80 },
13890c0d06caSMauro Carvalho Chehab { 0x3e, 0x80 },
13900c0d06caSMauro Carvalho Chehab { 0x3f, 0x0e },
13910c0d06caSMauro Carvalho Chehab { 0x40, 0x00 }, /* White bal */
13920c0d06caSMauro Carvalho Chehab { 0x41, 0x00 }, /* White bal */
13930c0d06caSMauro Carvalho Chehab { 0x42, 0x80 },
13940c0d06caSMauro Carvalho Chehab { 0x43, 0x3f }, /* White bal */
13950c0d06caSMauro Carvalho Chehab { 0x44, 0x80 },
13960c0d06caSMauro Carvalho Chehab { 0x45, 0x20 },
13970c0d06caSMauro Carvalho Chehab { 0x46, 0x20 },
13980c0d06caSMauro Carvalho Chehab { 0x47, 0x80 },
13990c0d06caSMauro Carvalho Chehab { 0x48, 0x7f },
14000c0d06caSMauro Carvalho Chehab { 0x49, 0x00 },
14010c0d06caSMauro Carvalho Chehab { 0x4a, 0x00 },
14020c0d06caSMauro Carvalho Chehab { 0x4b, 0x80 },
14030c0d06caSMauro Carvalho Chehab { 0x4c, 0xd0 },
14040c0d06caSMauro Carvalho Chehab { 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */
14050c0d06caSMauro Carvalho Chehab { 0x4e, 0x40 },
14060c0d06caSMauro Carvalho Chehab { 0x4f, 0x07 }, /* UV avg., col. killer: max */
14070c0d06caSMauro Carvalho Chehab { 0x50, 0xff },
14080c0d06caSMauro Carvalho Chehab { 0x54, 0x23 }, /* Max AGC gain: 18dB */
14090c0d06caSMauro Carvalho Chehab { 0x55, 0xff },
14100c0d06caSMauro Carvalho Chehab { 0x56, 0x12 },
14110c0d06caSMauro Carvalho Chehab { 0x57, 0x81 },
14120c0d06caSMauro Carvalho Chehab { 0x58, 0x75 },
14130c0d06caSMauro Carvalho Chehab { 0x59, 0x01 }, /* AGC dark current comp.: +1 */
14140c0d06caSMauro Carvalho Chehab { 0x5a, 0x2c },
14150c0d06caSMauro Carvalho Chehab { 0x5b, 0x0f }, /* AWB chrominance levels */
14160c0d06caSMauro Carvalho Chehab { 0x5c, 0x10 },
14170c0d06caSMauro Carvalho Chehab { 0x3d, 0x80 },
14180c0d06caSMauro Carvalho Chehab { 0x27, 0xa6 },
14190c0d06caSMauro Carvalho Chehab { 0x12, 0x20 }, /* Toggle AWB */
14200c0d06caSMauro Carvalho Chehab { 0x12, 0x24 },
14210c0d06caSMauro Carvalho Chehab };
14220c0d06caSMauro Carvalho Chehab
14230c0d06caSMauro Carvalho Chehab /* Lawrence Glaister <lg@jfm.bc.ca> reports:
14240c0d06caSMauro Carvalho Chehab *
14250c0d06caSMauro Carvalho Chehab * Register 0x0f in the 7610 has the following effects:
14260c0d06caSMauro Carvalho Chehab *
14270c0d06caSMauro Carvalho Chehab * 0x85 (AEC method 1): Best overall, good contrast range
14280c0d06caSMauro Carvalho Chehab * 0x45 (AEC method 2): Very overexposed
14290c0d06caSMauro Carvalho Chehab * 0xa5 (spec sheet default): Ok, but the black level is
14300c0d06caSMauro Carvalho Chehab * shifted resulting in loss of contrast
14310c0d06caSMauro Carvalho Chehab * 0x05 (old driver setting): very overexposed, too much
14320c0d06caSMauro Carvalho Chehab * contrast
14330c0d06caSMauro Carvalho Chehab */
14340c0d06caSMauro Carvalho Chehab static const struct ov_i2c_regvals norm_7610[] = {
14350c0d06caSMauro Carvalho Chehab { 0x10, 0xff },
14360c0d06caSMauro Carvalho Chehab { 0x16, 0x06 },
14370c0d06caSMauro Carvalho Chehab { 0x28, 0x24 },
14380c0d06caSMauro Carvalho Chehab { 0x2b, 0xac },
14390c0d06caSMauro Carvalho Chehab { 0x12, 0x00 },
14400c0d06caSMauro Carvalho Chehab { 0x38, 0x81 },
14410c0d06caSMauro Carvalho Chehab { 0x28, 0x24 }, /* 0c */
14420c0d06caSMauro Carvalho Chehab { 0x0f, 0x85 }, /* lg's setting */
14430c0d06caSMauro Carvalho Chehab { 0x15, 0x01 },
14440c0d06caSMauro Carvalho Chehab { 0x20, 0x1c },
14450c0d06caSMauro Carvalho Chehab { 0x23, 0x2a },
14460c0d06caSMauro Carvalho Chehab { 0x24, 0x10 },
14470c0d06caSMauro Carvalho Chehab { 0x25, 0x8a },
14480c0d06caSMauro Carvalho Chehab { 0x26, 0xa2 },
14490c0d06caSMauro Carvalho Chehab { 0x27, 0xc2 },
14500c0d06caSMauro Carvalho Chehab { 0x2a, 0x04 },
14510c0d06caSMauro Carvalho Chehab { 0x2c, 0xfe },
14520c0d06caSMauro Carvalho Chehab { 0x2d, 0x93 },
14530c0d06caSMauro Carvalho Chehab { 0x30, 0x71 },
14540c0d06caSMauro Carvalho Chehab { 0x31, 0x60 },
14550c0d06caSMauro Carvalho Chehab { 0x32, 0x26 },
14560c0d06caSMauro Carvalho Chehab { 0x33, 0x20 },
14570c0d06caSMauro Carvalho Chehab { 0x34, 0x48 },
14580c0d06caSMauro Carvalho Chehab { 0x12, 0x24 },
14590c0d06caSMauro Carvalho Chehab { 0x11, 0x01 },
14600c0d06caSMauro Carvalho Chehab { 0x0c, 0x24 },
14610c0d06caSMauro Carvalho Chehab { 0x0d, 0x24 },
14620c0d06caSMauro Carvalho Chehab };
14630c0d06caSMauro Carvalho Chehab
14640c0d06caSMauro Carvalho Chehab static const struct ov_i2c_regvals norm_7620[] = {
14650c0d06caSMauro Carvalho Chehab { 0x12, 0x80 }, /* reset */
14660c0d06caSMauro Carvalho Chehab { 0x00, 0x00 }, /* gain */
14670c0d06caSMauro Carvalho Chehab { 0x01, 0x80 }, /* blue gain */
14680c0d06caSMauro Carvalho Chehab { 0x02, 0x80 }, /* red gain */
14690c0d06caSMauro Carvalho Chehab { 0x03, 0xc0 }, /* OV7670_R03_VREF */
14700c0d06caSMauro Carvalho Chehab { 0x06, 0x60 },
14710c0d06caSMauro Carvalho Chehab { 0x07, 0x00 },
14720c0d06caSMauro Carvalho Chehab { 0x0c, 0x24 },
14730c0d06caSMauro Carvalho Chehab { 0x0c, 0x24 },
14740c0d06caSMauro Carvalho Chehab { 0x0d, 0x24 },
14750c0d06caSMauro Carvalho Chehab { 0x11, 0x01 },
14760c0d06caSMauro Carvalho Chehab { 0x12, 0x24 },
14770c0d06caSMauro Carvalho Chehab { 0x13, 0x01 },
14780c0d06caSMauro Carvalho Chehab { 0x14, 0x84 },
14790c0d06caSMauro Carvalho Chehab { 0x15, 0x01 },
14800c0d06caSMauro Carvalho Chehab { 0x16, 0x03 },
14810c0d06caSMauro Carvalho Chehab { 0x17, 0x2f },
14820c0d06caSMauro Carvalho Chehab { 0x18, 0xcf },
14830c0d06caSMauro Carvalho Chehab { 0x19, 0x06 },
14840c0d06caSMauro Carvalho Chehab { 0x1a, 0xf5 },
14850c0d06caSMauro Carvalho Chehab { 0x1b, 0x00 },
14860c0d06caSMauro Carvalho Chehab { 0x20, 0x18 },
14870c0d06caSMauro Carvalho Chehab { 0x21, 0x80 },
14880c0d06caSMauro Carvalho Chehab { 0x22, 0x80 },
14890c0d06caSMauro Carvalho Chehab { 0x23, 0x00 },
14900c0d06caSMauro Carvalho Chehab { 0x26, 0xa2 },
14910c0d06caSMauro Carvalho Chehab { 0x27, 0xea },
14920c0d06caSMauro Carvalho Chehab { 0x28, 0x22 }, /* Was 0x20, bit1 enables a 2x gain which we need */
14930c0d06caSMauro Carvalho Chehab { 0x29, 0x00 },
14940c0d06caSMauro Carvalho Chehab { 0x2a, 0x10 },
14950c0d06caSMauro Carvalho Chehab { 0x2b, 0x00 },
14960c0d06caSMauro Carvalho Chehab { 0x2c, 0x88 },
14970c0d06caSMauro Carvalho Chehab { 0x2d, 0x91 },
14980c0d06caSMauro Carvalho Chehab { 0x2e, 0x80 },
14990c0d06caSMauro Carvalho Chehab { 0x2f, 0x44 },
15000c0d06caSMauro Carvalho Chehab { 0x60, 0x27 },
15010c0d06caSMauro Carvalho Chehab { 0x61, 0x02 },
15020c0d06caSMauro Carvalho Chehab { 0x62, 0x5f },
15030c0d06caSMauro Carvalho Chehab { 0x63, 0xd5 },
15040c0d06caSMauro Carvalho Chehab { 0x64, 0x57 },
15050c0d06caSMauro Carvalho Chehab { 0x65, 0x83 },
15060c0d06caSMauro Carvalho Chehab { 0x66, 0x55 },
15070c0d06caSMauro Carvalho Chehab { 0x67, 0x92 },
15080c0d06caSMauro Carvalho Chehab { 0x68, 0xcf },
15090c0d06caSMauro Carvalho Chehab { 0x69, 0x76 },
15100c0d06caSMauro Carvalho Chehab { 0x6a, 0x22 },
15110c0d06caSMauro Carvalho Chehab { 0x6b, 0x00 },
15120c0d06caSMauro Carvalho Chehab { 0x6c, 0x02 },
15130c0d06caSMauro Carvalho Chehab { 0x6d, 0x44 },
15140c0d06caSMauro Carvalho Chehab { 0x6e, 0x80 },
15150c0d06caSMauro Carvalho Chehab { 0x6f, 0x1d },
15160c0d06caSMauro Carvalho Chehab { 0x70, 0x8b },
15170c0d06caSMauro Carvalho Chehab { 0x71, 0x00 },
15180c0d06caSMauro Carvalho Chehab { 0x72, 0x14 },
15190c0d06caSMauro Carvalho Chehab { 0x73, 0x54 },
15200c0d06caSMauro Carvalho Chehab { 0x74, 0x00 },
15210c0d06caSMauro Carvalho Chehab { 0x75, 0x8e },
15220c0d06caSMauro Carvalho Chehab { 0x76, 0x00 },
15230c0d06caSMauro Carvalho Chehab { 0x77, 0xff },
15240c0d06caSMauro Carvalho Chehab { 0x78, 0x80 },
15250c0d06caSMauro Carvalho Chehab { 0x79, 0x80 },
15260c0d06caSMauro Carvalho Chehab { 0x7a, 0x80 },
15270c0d06caSMauro Carvalho Chehab { 0x7b, 0xe2 },
15280c0d06caSMauro Carvalho Chehab { 0x7c, 0x00 },
15290c0d06caSMauro Carvalho Chehab };
15300c0d06caSMauro Carvalho Chehab
15310c0d06caSMauro Carvalho Chehab /* 7640 and 7648. The defaults should be OK for most registers. */
15320c0d06caSMauro Carvalho Chehab static const struct ov_i2c_regvals norm_7640[] = {
15330c0d06caSMauro Carvalho Chehab { 0x12, 0x80 },
15340c0d06caSMauro Carvalho Chehab { 0x12, 0x14 },
15350c0d06caSMauro Carvalho Chehab };
15360c0d06caSMauro Carvalho Chehab
15370c0d06caSMauro Carvalho Chehab static const struct ov_regvals init_519_ov7660[] = {
15380c0d06caSMauro Carvalho Chehab { 0x5d, 0x03 }, /* Turn off suspend mode */
15390c0d06caSMauro Carvalho Chehab { 0x53, 0x9b }, /* 0x9f enables the (unused) microcontroller */
15400c0d06caSMauro Carvalho Chehab { 0x54, 0x0f }, /* bit2 (jpeg enable) */
15410c0d06caSMauro Carvalho Chehab { 0xa2, 0x20 }, /* a2-a5 are undocumented */
15420c0d06caSMauro Carvalho Chehab { 0xa3, 0x18 },
15430c0d06caSMauro Carvalho Chehab { 0xa4, 0x04 },
15440c0d06caSMauro Carvalho Chehab { 0xa5, 0x28 },
15450c0d06caSMauro Carvalho Chehab { 0x37, 0x00 }, /* SetUsbInit */
15460c0d06caSMauro Carvalho Chehab { 0x55, 0x02 }, /* 4.096 Mhz audio clock */
15470c0d06caSMauro Carvalho Chehab /* Enable both fields, YUV Input, disable defect comp (why?) */
15480c0d06caSMauro Carvalho Chehab { 0x20, 0x0c }, /* 0x0d does U <-> V swap */
15490c0d06caSMauro Carvalho Chehab { 0x21, 0x38 },
15500c0d06caSMauro Carvalho Chehab { 0x22, 0x1d },
15510c0d06caSMauro Carvalho Chehab { 0x17, 0x50 }, /* undocumented */
15520c0d06caSMauro Carvalho Chehab { 0x37, 0x00 }, /* undocumented */
15530c0d06caSMauro Carvalho Chehab { 0x40, 0xff }, /* I2C timeout counter */
15540c0d06caSMauro Carvalho Chehab { 0x46, 0x00 }, /* I2C clock prescaler */
15550c0d06caSMauro Carvalho Chehab };
15560c0d06caSMauro Carvalho Chehab static const struct ov_i2c_regvals norm_7660[] = {
15570c0d06caSMauro Carvalho Chehab {OV7670_R12_COM7, OV7670_COM7_RESET},
15580c0d06caSMauro Carvalho Chehab {OV7670_R11_CLKRC, 0x81},
15590c0d06caSMauro Carvalho Chehab {0x92, 0x00}, /* DM_LNL */
15600c0d06caSMauro Carvalho Chehab {0x93, 0x00}, /* DM_LNH */
15610c0d06caSMauro Carvalho Chehab {0x9d, 0x4c}, /* BD50ST */
15620c0d06caSMauro Carvalho Chehab {0x9e, 0x3f}, /* BD60ST */
15630c0d06caSMauro Carvalho Chehab {OV7670_R3B_COM11, 0x02},
15640c0d06caSMauro Carvalho Chehab {OV7670_R13_COM8, 0xf5},
15650c0d06caSMauro Carvalho Chehab {OV7670_R10_AECH, 0x00},
15660c0d06caSMauro Carvalho Chehab {OV7670_R00_GAIN, 0x00},
15670c0d06caSMauro Carvalho Chehab {OV7670_R01_BLUE, 0x7c},
15680c0d06caSMauro Carvalho Chehab {OV7670_R02_RED, 0x9d},
15690c0d06caSMauro Carvalho Chehab {OV7670_R12_COM7, 0x00},
15700c0d06caSMauro Carvalho Chehab {OV7670_R04_COM1, 00},
15710c0d06caSMauro Carvalho Chehab {OV7670_R18_HSTOP, 0x01},
15720c0d06caSMauro Carvalho Chehab {OV7670_R17_HSTART, 0x13},
15730c0d06caSMauro Carvalho Chehab {OV7670_R32_HREF, 0x92},
15740c0d06caSMauro Carvalho Chehab {OV7670_R19_VSTART, 0x02},
15750c0d06caSMauro Carvalho Chehab {OV7670_R1A_VSTOP, 0x7a},
15760c0d06caSMauro Carvalho Chehab {OV7670_R03_VREF, 0x00},
15770c0d06caSMauro Carvalho Chehab {OV7670_R0E_COM5, 0x04},
15780c0d06caSMauro Carvalho Chehab {OV7670_R0F_COM6, 0x62},
15790c0d06caSMauro Carvalho Chehab {OV7670_R15_COM10, 0x00},
15800c0d06caSMauro Carvalho Chehab {0x16, 0x02}, /* RSVD */
15810c0d06caSMauro Carvalho Chehab {0x1b, 0x00}, /* PSHFT */
15820c0d06caSMauro Carvalho Chehab {OV7670_R1E_MVFP, 0x01},
15830c0d06caSMauro Carvalho Chehab {0x29, 0x3c}, /* RSVD */
15840c0d06caSMauro Carvalho Chehab {0x33, 0x00}, /* CHLF */
15850c0d06caSMauro Carvalho Chehab {0x34, 0x07}, /* ARBLM */
15860c0d06caSMauro Carvalho Chehab {0x35, 0x84}, /* RSVD */
15870c0d06caSMauro Carvalho Chehab {0x36, 0x00}, /* RSVD */
15880c0d06caSMauro Carvalho Chehab {0x37, 0x04}, /* ADC */
15890c0d06caSMauro Carvalho Chehab {0x39, 0x43}, /* OFON */
15900c0d06caSMauro Carvalho Chehab {OV7670_R3A_TSLB, 0x00},
15910c0d06caSMauro Carvalho Chehab {OV7670_R3C_COM12, 0x6c},
15920c0d06caSMauro Carvalho Chehab {OV7670_R3D_COM13, 0x98},
15930c0d06caSMauro Carvalho Chehab {OV7670_R3F_EDGE, 0x23},
15940c0d06caSMauro Carvalho Chehab {OV7670_R40_COM15, 0xc1},
15950c0d06caSMauro Carvalho Chehab {OV7670_R41_COM16, 0x22},
15960c0d06caSMauro Carvalho Chehab {0x6b, 0x0a}, /* DBLV */
15970c0d06caSMauro Carvalho Chehab {0xa1, 0x08}, /* RSVD */
15980c0d06caSMauro Carvalho Chehab {0x69, 0x80}, /* HV */
15990c0d06caSMauro Carvalho Chehab {0x43, 0xf0}, /* RSVD.. */
16000c0d06caSMauro Carvalho Chehab {0x44, 0x10},
16010c0d06caSMauro Carvalho Chehab {0x45, 0x78},
16020c0d06caSMauro Carvalho Chehab {0x46, 0xa8},
16030c0d06caSMauro Carvalho Chehab {0x47, 0x60},
16040c0d06caSMauro Carvalho Chehab {0x48, 0x80},
16050c0d06caSMauro Carvalho Chehab {0x59, 0xba},
16060c0d06caSMauro Carvalho Chehab {0x5a, 0x9a},
16070c0d06caSMauro Carvalho Chehab {0x5b, 0x22},
16080c0d06caSMauro Carvalho Chehab {0x5c, 0xb9},
16090c0d06caSMauro Carvalho Chehab {0x5d, 0x9b},
16100c0d06caSMauro Carvalho Chehab {0x5e, 0x10},
16110c0d06caSMauro Carvalho Chehab {0x5f, 0xe0},
16120c0d06caSMauro Carvalho Chehab {0x60, 0x85},
16130c0d06caSMauro Carvalho Chehab {0x61, 0x60},
16140c0d06caSMauro Carvalho Chehab {0x9f, 0x9d}, /* RSVD */
16150c0d06caSMauro Carvalho Chehab {0xa0, 0xa0}, /* DSPC2 */
16160c0d06caSMauro Carvalho Chehab {0x4f, 0x60}, /* matrix */
16170c0d06caSMauro Carvalho Chehab {0x50, 0x64},
16180c0d06caSMauro Carvalho Chehab {0x51, 0x04},
16190c0d06caSMauro Carvalho Chehab {0x52, 0x18},
16200c0d06caSMauro Carvalho Chehab {0x53, 0x3c},
16210c0d06caSMauro Carvalho Chehab {0x54, 0x54},
16220c0d06caSMauro Carvalho Chehab {0x55, 0x40},
16230c0d06caSMauro Carvalho Chehab {0x56, 0x40},
16240c0d06caSMauro Carvalho Chehab {0x57, 0x40},
16250c0d06caSMauro Carvalho Chehab {0x58, 0x0d}, /* matrix sign */
16260c0d06caSMauro Carvalho Chehab {0x8b, 0xcc}, /* RSVD */
16270c0d06caSMauro Carvalho Chehab {0x8c, 0xcc},
16280c0d06caSMauro Carvalho Chehab {0x8d, 0xcf},
16290c0d06caSMauro Carvalho Chehab {0x6c, 0x40}, /* gamma curve */
16300c0d06caSMauro Carvalho Chehab {0x6d, 0xe0},
16310c0d06caSMauro Carvalho Chehab {0x6e, 0xa0},
16320c0d06caSMauro Carvalho Chehab {0x6f, 0x80},
16330c0d06caSMauro Carvalho Chehab {0x70, 0x70},
16340c0d06caSMauro Carvalho Chehab {0x71, 0x80},
16350c0d06caSMauro Carvalho Chehab {0x72, 0x60},
16360c0d06caSMauro Carvalho Chehab {0x73, 0x60},
16370c0d06caSMauro Carvalho Chehab {0x74, 0x50},
16380c0d06caSMauro Carvalho Chehab {0x75, 0x40},
16390c0d06caSMauro Carvalho Chehab {0x76, 0x38},
16400c0d06caSMauro Carvalho Chehab {0x77, 0x3c},
16410c0d06caSMauro Carvalho Chehab {0x78, 0x32},
16420c0d06caSMauro Carvalho Chehab {0x79, 0x1a},
16430c0d06caSMauro Carvalho Chehab {0x7a, 0x28},
16440c0d06caSMauro Carvalho Chehab {0x7b, 0x24},
16450c0d06caSMauro Carvalho Chehab {0x7c, 0x04}, /* gamma curve */
16460c0d06caSMauro Carvalho Chehab {0x7d, 0x12},
16470c0d06caSMauro Carvalho Chehab {0x7e, 0x26},
16480c0d06caSMauro Carvalho Chehab {0x7f, 0x46},
16490c0d06caSMauro Carvalho Chehab {0x80, 0x54},
16500c0d06caSMauro Carvalho Chehab {0x81, 0x64},
16510c0d06caSMauro Carvalho Chehab {0x82, 0x70},
16520c0d06caSMauro Carvalho Chehab {0x83, 0x7c},
16530c0d06caSMauro Carvalho Chehab {0x84, 0x86},
16540c0d06caSMauro Carvalho Chehab {0x85, 0x8e},
16550c0d06caSMauro Carvalho Chehab {0x86, 0x9c},
16560c0d06caSMauro Carvalho Chehab {0x87, 0xab},
16570c0d06caSMauro Carvalho Chehab {0x88, 0xc4},
16580c0d06caSMauro Carvalho Chehab {0x89, 0xd1},
16590c0d06caSMauro Carvalho Chehab {0x8a, 0xe5},
16600c0d06caSMauro Carvalho Chehab {OV7670_R14_COM9, 0x1e},
16610c0d06caSMauro Carvalho Chehab {OV7670_R24_AEW, 0x80},
16620c0d06caSMauro Carvalho Chehab {OV7670_R25_AEB, 0x72},
16630c0d06caSMauro Carvalho Chehab {OV7670_R26_VPT, 0xb3},
16640c0d06caSMauro Carvalho Chehab {0x62, 0x80}, /* LCC1 */
16650c0d06caSMauro Carvalho Chehab {0x63, 0x80}, /* LCC2 */
16660c0d06caSMauro Carvalho Chehab {0x64, 0x06}, /* LCC3 */
16670c0d06caSMauro Carvalho Chehab {0x65, 0x00}, /* LCC4 */
16680c0d06caSMauro Carvalho Chehab {0x66, 0x01}, /* LCC5 */
16690c0d06caSMauro Carvalho Chehab {0x94, 0x0e}, /* RSVD.. */
16700c0d06caSMauro Carvalho Chehab {0x95, 0x14},
16710c0d06caSMauro Carvalho Chehab {OV7670_R13_COM8, OV7670_COM8_FASTAEC
16720c0d06caSMauro Carvalho Chehab | OV7670_COM8_AECSTEP
16730c0d06caSMauro Carvalho Chehab | OV7670_COM8_BFILT
16740c0d06caSMauro Carvalho Chehab | 0x10
16750c0d06caSMauro Carvalho Chehab | OV7670_COM8_AGC
16760c0d06caSMauro Carvalho Chehab | OV7670_COM8_AWB
16770c0d06caSMauro Carvalho Chehab | OV7670_COM8_AEC},
16780c0d06caSMauro Carvalho Chehab {0xa1, 0xc8}
16790c0d06caSMauro Carvalho Chehab };
16800c0d06caSMauro Carvalho Chehab static const struct ov_i2c_regvals norm_9600[] = {
16810c0d06caSMauro Carvalho Chehab {0x12, 0x80},
16820c0d06caSMauro Carvalho Chehab {0x0c, 0x28},
16830c0d06caSMauro Carvalho Chehab {0x11, 0x80},
16840c0d06caSMauro Carvalho Chehab {0x13, 0xb5},
16850c0d06caSMauro Carvalho Chehab {0x14, 0x3e},
16860c0d06caSMauro Carvalho Chehab {0x1b, 0x04},
16870c0d06caSMauro Carvalho Chehab {0x24, 0xb0},
16880c0d06caSMauro Carvalho Chehab {0x25, 0x90},
16890c0d06caSMauro Carvalho Chehab {0x26, 0x94},
16900c0d06caSMauro Carvalho Chehab {0x35, 0x90},
16910c0d06caSMauro Carvalho Chehab {0x37, 0x07},
16920c0d06caSMauro Carvalho Chehab {0x38, 0x08},
16930c0d06caSMauro Carvalho Chehab {0x01, 0x8e},
16940c0d06caSMauro Carvalho Chehab {0x02, 0x85}
16950c0d06caSMauro Carvalho Chehab };
16960c0d06caSMauro Carvalho Chehab
16970c0d06caSMauro Carvalho Chehab /* 7670. Defaults taken from OmniVision provided data,
16980c0d06caSMauro Carvalho Chehab * as provided by Jonathan Corbet of OLPC */
16990c0d06caSMauro Carvalho Chehab static const struct ov_i2c_regvals norm_7670[] = {
17000c0d06caSMauro Carvalho Chehab { OV7670_R12_COM7, OV7670_COM7_RESET },
17010c0d06caSMauro Carvalho Chehab { OV7670_R3A_TSLB, 0x04 }, /* OV */
17020c0d06caSMauro Carvalho Chehab { OV7670_R12_COM7, OV7670_COM7_FMT_VGA }, /* VGA */
17030c0d06caSMauro Carvalho Chehab { OV7670_R11_CLKRC, 0x01 },
17040c0d06caSMauro Carvalho Chehab /*
17050c0d06caSMauro Carvalho Chehab * Set the hardware window. These values from OV don't entirely
17060c0d06caSMauro Carvalho Chehab * make sense - hstop is less than hstart. But they work...
17070c0d06caSMauro Carvalho Chehab */
17080c0d06caSMauro Carvalho Chehab { OV7670_R17_HSTART, 0x13 },
17090c0d06caSMauro Carvalho Chehab { OV7670_R18_HSTOP, 0x01 },
17100c0d06caSMauro Carvalho Chehab { OV7670_R32_HREF, 0xb6 },
17110c0d06caSMauro Carvalho Chehab { OV7670_R19_VSTART, 0x02 },
17120c0d06caSMauro Carvalho Chehab { OV7670_R1A_VSTOP, 0x7a },
17130c0d06caSMauro Carvalho Chehab { OV7670_R03_VREF, 0x0a },
17140c0d06caSMauro Carvalho Chehab
17150c0d06caSMauro Carvalho Chehab { OV7670_R0C_COM3, 0x00 },
17160c0d06caSMauro Carvalho Chehab { OV7670_R3E_COM14, 0x00 },
17170c0d06caSMauro Carvalho Chehab /* Mystery scaling numbers */
17180c0d06caSMauro Carvalho Chehab { 0x70, 0x3a },
17190c0d06caSMauro Carvalho Chehab { 0x71, 0x35 },
17200c0d06caSMauro Carvalho Chehab { 0x72, 0x11 },
17210c0d06caSMauro Carvalho Chehab { 0x73, 0xf0 },
17220c0d06caSMauro Carvalho Chehab { 0xa2, 0x02 },
17230c0d06caSMauro Carvalho Chehab /* { OV7670_R15_COM10, 0x0 }, */
17240c0d06caSMauro Carvalho Chehab
17250c0d06caSMauro Carvalho Chehab /* Gamma curve values */
17260c0d06caSMauro Carvalho Chehab { 0x7a, 0x20 },
17270c0d06caSMauro Carvalho Chehab { 0x7b, 0x10 },
17280c0d06caSMauro Carvalho Chehab { 0x7c, 0x1e },
17290c0d06caSMauro Carvalho Chehab { 0x7d, 0x35 },
17300c0d06caSMauro Carvalho Chehab { 0x7e, 0x5a },
17310c0d06caSMauro Carvalho Chehab { 0x7f, 0x69 },
17320c0d06caSMauro Carvalho Chehab { 0x80, 0x76 },
17330c0d06caSMauro Carvalho Chehab { 0x81, 0x80 },
17340c0d06caSMauro Carvalho Chehab { 0x82, 0x88 },
17350c0d06caSMauro Carvalho Chehab { 0x83, 0x8f },
17360c0d06caSMauro Carvalho Chehab { 0x84, 0x96 },
17370c0d06caSMauro Carvalho Chehab { 0x85, 0xa3 },
17380c0d06caSMauro Carvalho Chehab { 0x86, 0xaf },
17390c0d06caSMauro Carvalho Chehab { 0x87, 0xc4 },
17400c0d06caSMauro Carvalho Chehab { 0x88, 0xd7 },
17410c0d06caSMauro Carvalho Chehab { 0x89, 0xe8 },
17420c0d06caSMauro Carvalho Chehab
17430c0d06caSMauro Carvalho Chehab /* AGC and AEC parameters. Note we start by disabling those features,
17440c0d06caSMauro Carvalho Chehab then turn them only after tweaking the values. */
17450c0d06caSMauro Carvalho Chehab { OV7670_R13_COM8, OV7670_COM8_FASTAEC
17460c0d06caSMauro Carvalho Chehab | OV7670_COM8_AECSTEP
17470c0d06caSMauro Carvalho Chehab | OV7670_COM8_BFILT },
17480c0d06caSMauro Carvalho Chehab { OV7670_R00_GAIN, 0x00 },
17490c0d06caSMauro Carvalho Chehab { OV7670_R10_AECH, 0x00 },
17500c0d06caSMauro Carvalho Chehab { OV7670_R0D_COM4, 0x40 }, /* magic reserved bit */
17510c0d06caSMauro Carvalho Chehab { OV7670_R14_COM9, 0x18 }, /* 4x gain + magic rsvd bit */
17520c0d06caSMauro Carvalho Chehab { OV7670_RA5_BD50MAX, 0x05 },
17530c0d06caSMauro Carvalho Chehab { OV7670_RAB_BD60MAX, 0x07 },
17540c0d06caSMauro Carvalho Chehab { OV7670_R24_AEW, 0x95 },
17550c0d06caSMauro Carvalho Chehab { OV7670_R25_AEB, 0x33 },
17560c0d06caSMauro Carvalho Chehab { OV7670_R26_VPT, 0xe3 },
17570c0d06caSMauro Carvalho Chehab { OV7670_R9F_HAECC1, 0x78 },
17580c0d06caSMauro Carvalho Chehab { OV7670_RA0_HAECC2, 0x68 },
17590c0d06caSMauro Carvalho Chehab { 0xa1, 0x03 }, /* magic */
17600c0d06caSMauro Carvalho Chehab { OV7670_RA6_HAECC3, 0xd8 },
17610c0d06caSMauro Carvalho Chehab { OV7670_RA7_HAECC4, 0xd8 },
17620c0d06caSMauro Carvalho Chehab { OV7670_RA8_HAECC5, 0xf0 },
17630c0d06caSMauro Carvalho Chehab { OV7670_RA9_HAECC6, 0x90 },
17640c0d06caSMauro Carvalho Chehab { OV7670_RAA_HAECC7, 0x94 },
17650c0d06caSMauro Carvalho Chehab { OV7670_R13_COM8, OV7670_COM8_FASTAEC
17660c0d06caSMauro Carvalho Chehab | OV7670_COM8_AECSTEP
17670c0d06caSMauro Carvalho Chehab | OV7670_COM8_BFILT
17680c0d06caSMauro Carvalho Chehab | OV7670_COM8_AGC
17690c0d06caSMauro Carvalho Chehab | OV7670_COM8_AEC },
17700c0d06caSMauro Carvalho Chehab
17710c0d06caSMauro Carvalho Chehab /* Almost all of these are magic "reserved" values. */
17720c0d06caSMauro Carvalho Chehab { OV7670_R0E_COM5, 0x61 },
17730c0d06caSMauro Carvalho Chehab { OV7670_R0F_COM6, 0x4b },
17740c0d06caSMauro Carvalho Chehab { 0x16, 0x02 },
17750c0d06caSMauro Carvalho Chehab { OV7670_R1E_MVFP, 0x07 },
17760c0d06caSMauro Carvalho Chehab { 0x21, 0x02 },
17770c0d06caSMauro Carvalho Chehab { 0x22, 0x91 },
17780c0d06caSMauro Carvalho Chehab { 0x29, 0x07 },
17790c0d06caSMauro Carvalho Chehab { 0x33, 0x0b },
17800c0d06caSMauro Carvalho Chehab { 0x35, 0x0b },
17810c0d06caSMauro Carvalho Chehab { 0x37, 0x1d },
17820c0d06caSMauro Carvalho Chehab { 0x38, 0x71 },
17830c0d06caSMauro Carvalho Chehab { 0x39, 0x2a },
17840c0d06caSMauro Carvalho Chehab { OV7670_R3C_COM12, 0x78 },
17850c0d06caSMauro Carvalho Chehab { 0x4d, 0x40 },
17860c0d06caSMauro Carvalho Chehab { 0x4e, 0x20 },
17870c0d06caSMauro Carvalho Chehab { OV7670_R69_GFIX, 0x00 },
17880c0d06caSMauro Carvalho Chehab { 0x6b, 0x4a },
17890c0d06caSMauro Carvalho Chehab { 0x74, 0x10 },
17900c0d06caSMauro Carvalho Chehab { 0x8d, 0x4f },
17910c0d06caSMauro Carvalho Chehab { 0x8e, 0x00 },
17920c0d06caSMauro Carvalho Chehab { 0x8f, 0x00 },
17930c0d06caSMauro Carvalho Chehab { 0x90, 0x00 },
17940c0d06caSMauro Carvalho Chehab { 0x91, 0x00 },
17950c0d06caSMauro Carvalho Chehab { 0x96, 0x00 },
17960c0d06caSMauro Carvalho Chehab { 0x9a, 0x00 },
17970c0d06caSMauro Carvalho Chehab { 0xb0, 0x84 },
17980c0d06caSMauro Carvalho Chehab { 0xb1, 0x0c },
17990c0d06caSMauro Carvalho Chehab { 0xb2, 0x0e },
18000c0d06caSMauro Carvalho Chehab { 0xb3, 0x82 },
18010c0d06caSMauro Carvalho Chehab { 0xb8, 0x0a },
18020c0d06caSMauro Carvalho Chehab
18030c0d06caSMauro Carvalho Chehab /* More reserved magic, some of which tweaks white balance */
18040c0d06caSMauro Carvalho Chehab { 0x43, 0x0a },
18050c0d06caSMauro Carvalho Chehab { 0x44, 0xf0 },
18060c0d06caSMauro Carvalho Chehab { 0x45, 0x34 },
18070c0d06caSMauro Carvalho Chehab { 0x46, 0x58 },
18080c0d06caSMauro Carvalho Chehab { 0x47, 0x28 },
18090c0d06caSMauro Carvalho Chehab { 0x48, 0x3a },
18100c0d06caSMauro Carvalho Chehab { 0x59, 0x88 },
18110c0d06caSMauro Carvalho Chehab { 0x5a, 0x88 },
18120c0d06caSMauro Carvalho Chehab { 0x5b, 0x44 },
18130c0d06caSMauro Carvalho Chehab { 0x5c, 0x67 },
18140c0d06caSMauro Carvalho Chehab { 0x5d, 0x49 },
18150c0d06caSMauro Carvalho Chehab { 0x5e, 0x0e },
18160c0d06caSMauro Carvalho Chehab { 0x6c, 0x0a },
18170c0d06caSMauro Carvalho Chehab { 0x6d, 0x55 },
18180c0d06caSMauro Carvalho Chehab { 0x6e, 0x11 },
18190c0d06caSMauro Carvalho Chehab { 0x6f, 0x9f }, /* "9e for advance AWB" */
18200c0d06caSMauro Carvalho Chehab { 0x6a, 0x40 },
18210c0d06caSMauro Carvalho Chehab { OV7670_R01_BLUE, 0x40 },
18220c0d06caSMauro Carvalho Chehab { OV7670_R02_RED, 0x60 },
18230c0d06caSMauro Carvalho Chehab { OV7670_R13_COM8, OV7670_COM8_FASTAEC
18240c0d06caSMauro Carvalho Chehab | OV7670_COM8_AECSTEP
18250c0d06caSMauro Carvalho Chehab | OV7670_COM8_BFILT
18260c0d06caSMauro Carvalho Chehab | OV7670_COM8_AGC
18270c0d06caSMauro Carvalho Chehab | OV7670_COM8_AEC
18280c0d06caSMauro Carvalho Chehab | OV7670_COM8_AWB },
18290c0d06caSMauro Carvalho Chehab
18300c0d06caSMauro Carvalho Chehab /* Matrix coefficients */
18310c0d06caSMauro Carvalho Chehab { 0x4f, 0x80 },
18320c0d06caSMauro Carvalho Chehab { 0x50, 0x80 },
18330c0d06caSMauro Carvalho Chehab { 0x51, 0x00 },
18340c0d06caSMauro Carvalho Chehab { 0x52, 0x22 },
18350c0d06caSMauro Carvalho Chehab { 0x53, 0x5e },
18360c0d06caSMauro Carvalho Chehab { 0x54, 0x80 },
18370c0d06caSMauro Carvalho Chehab { 0x58, 0x9e },
18380c0d06caSMauro Carvalho Chehab
18390c0d06caSMauro Carvalho Chehab { OV7670_R41_COM16, OV7670_COM16_AWBGAIN },
18400c0d06caSMauro Carvalho Chehab { OV7670_R3F_EDGE, 0x00 },
18410c0d06caSMauro Carvalho Chehab { 0x75, 0x05 },
18420c0d06caSMauro Carvalho Chehab { 0x76, 0xe1 },
18430c0d06caSMauro Carvalho Chehab { 0x4c, 0x00 },
18440c0d06caSMauro Carvalho Chehab { 0x77, 0x01 },
18450c0d06caSMauro Carvalho Chehab { OV7670_R3D_COM13, OV7670_COM13_GAMMA
18460c0d06caSMauro Carvalho Chehab | OV7670_COM13_UVSAT
18470c0d06caSMauro Carvalho Chehab | 2}, /* was 3 */
18480c0d06caSMauro Carvalho Chehab { 0x4b, 0x09 },
18490c0d06caSMauro Carvalho Chehab { 0xc9, 0x60 },
18500c0d06caSMauro Carvalho Chehab { OV7670_R41_COM16, 0x38 },
18510c0d06caSMauro Carvalho Chehab { 0x56, 0x40 },
18520c0d06caSMauro Carvalho Chehab
18530c0d06caSMauro Carvalho Chehab { 0x34, 0x11 },
18540c0d06caSMauro Carvalho Chehab { OV7670_R3B_COM11, OV7670_COM11_EXP|OV7670_COM11_HZAUTO },
18550c0d06caSMauro Carvalho Chehab { 0xa4, 0x88 },
18560c0d06caSMauro Carvalho Chehab { 0x96, 0x00 },
18570c0d06caSMauro Carvalho Chehab { 0x97, 0x30 },
18580c0d06caSMauro Carvalho Chehab { 0x98, 0x20 },
18590c0d06caSMauro Carvalho Chehab { 0x99, 0x30 },
18600c0d06caSMauro Carvalho Chehab { 0x9a, 0x84 },
18610c0d06caSMauro Carvalho Chehab { 0x9b, 0x29 },
18620c0d06caSMauro Carvalho Chehab { 0x9c, 0x03 },
18630c0d06caSMauro Carvalho Chehab { 0x9d, 0x4c },
18640c0d06caSMauro Carvalho Chehab { 0x9e, 0x3f },
18650c0d06caSMauro Carvalho Chehab { 0x78, 0x04 },
18660c0d06caSMauro Carvalho Chehab
18670c0d06caSMauro Carvalho Chehab /* Extra-weird stuff. Some sort of multiplexor register */
18680c0d06caSMauro Carvalho Chehab { 0x79, 0x01 },
18690c0d06caSMauro Carvalho Chehab { 0xc8, 0xf0 },
18700c0d06caSMauro Carvalho Chehab { 0x79, 0x0f },
18710c0d06caSMauro Carvalho Chehab { 0xc8, 0x00 },
18720c0d06caSMauro Carvalho Chehab { 0x79, 0x10 },
18730c0d06caSMauro Carvalho Chehab { 0xc8, 0x7e },
18740c0d06caSMauro Carvalho Chehab { 0x79, 0x0a },
18750c0d06caSMauro Carvalho Chehab { 0xc8, 0x80 },
18760c0d06caSMauro Carvalho Chehab { 0x79, 0x0b },
18770c0d06caSMauro Carvalho Chehab { 0xc8, 0x01 },
18780c0d06caSMauro Carvalho Chehab { 0x79, 0x0c },
18790c0d06caSMauro Carvalho Chehab { 0xc8, 0x0f },
18800c0d06caSMauro Carvalho Chehab { 0x79, 0x0d },
18810c0d06caSMauro Carvalho Chehab { 0xc8, 0x20 },
18820c0d06caSMauro Carvalho Chehab { 0x79, 0x09 },
18830c0d06caSMauro Carvalho Chehab { 0xc8, 0x80 },
18840c0d06caSMauro Carvalho Chehab { 0x79, 0x02 },
18850c0d06caSMauro Carvalho Chehab { 0xc8, 0xc0 },
18860c0d06caSMauro Carvalho Chehab { 0x79, 0x03 },
18870c0d06caSMauro Carvalho Chehab { 0xc8, 0x40 },
18880c0d06caSMauro Carvalho Chehab { 0x79, 0x05 },
18890c0d06caSMauro Carvalho Chehab { 0xc8, 0x30 },
18900c0d06caSMauro Carvalho Chehab { 0x79, 0x26 },
18910c0d06caSMauro Carvalho Chehab };
18920c0d06caSMauro Carvalho Chehab
18930c0d06caSMauro Carvalho Chehab static const struct ov_i2c_regvals norm_8610[] = {
18940c0d06caSMauro Carvalho Chehab { 0x12, 0x80 },
18950c0d06caSMauro Carvalho Chehab { 0x00, 0x00 },
18960c0d06caSMauro Carvalho Chehab { 0x01, 0x80 },
18970c0d06caSMauro Carvalho Chehab { 0x02, 0x80 },
18980c0d06caSMauro Carvalho Chehab { 0x03, 0xc0 },
18990c0d06caSMauro Carvalho Chehab { 0x04, 0x30 },
19000c0d06caSMauro Carvalho Chehab { 0x05, 0x30 }, /* was 0x10, new from windrv 090403 */
19010c0d06caSMauro Carvalho Chehab { 0x06, 0x70 }, /* was 0x80, new from windrv 090403 */
19020c0d06caSMauro Carvalho Chehab { 0x0a, 0x86 },
19030c0d06caSMauro Carvalho Chehab { 0x0b, 0xb0 },
19040c0d06caSMauro Carvalho Chehab { 0x0c, 0x20 },
19050c0d06caSMauro Carvalho Chehab { 0x0d, 0x20 },
19060c0d06caSMauro Carvalho Chehab { 0x11, 0x01 },
19070c0d06caSMauro Carvalho Chehab { 0x12, 0x25 },
19080c0d06caSMauro Carvalho Chehab { 0x13, 0x01 },
19090c0d06caSMauro Carvalho Chehab { 0x14, 0x04 },
19100c0d06caSMauro Carvalho Chehab { 0x15, 0x01 }, /* Lin and Win think different about UV order */
19110c0d06caSMauro Carvalho Chehab { 0x16, 0x03 },
19120c0d06caSMauro Carvalho Chehab { 0x17, 0x38 }, /* was 0x2f, new from windrv 090403 */
19130c0d06caSMauro Carvalho Chehab { 0x18, 0xea }, /* was 0xcf, new from windrv 090403 */
19140c0d06caSMauro Carvalho Chehab { 0x19, 0x02 }, /* was 0x06, new from windrv 090403 */
19150c0d06caSMauro Carvalho Chehab { 0x1a, 0xf5 },
19160c0d06caSMauro Carvalho Chehab { 0x1b, 0x00 },
19170c0d06caSMauro Carvalho Chehab { 0x20, 0xd0 }, /* was 0x90, new from windrv 090403 */
19180c0d06caSMauro Carvalho Chehab { 0x23, 0xc0 }, /* was 0x00, new from windrv 090403 */
19190c0d06caSMauro Carvalho Chehab { 0x24, 0x30 }, /* was 0x1d, new from windrv 090403 */
19200c0d06caSMauro Carvalho Chehab { 0x25, 0x50 }, /* was 0x57, new from windrv 090403 */
19210c0d06caSMauro Carvalho Chehab { 0x26, 0xa2 },
19220c0d06caSMauro Carvalho Chehab { 0x27, 0xea },
19230c0d06caSMauro Carvalho Chehab { 0x28, 0x00 },
19240c0d06caSMauro Carvalho Chehab { 0x29, 0x00 },
19250c0d06caSMauro Carvalho Chehab { 0x2a, 0x80 },
19260c0d06caSMauro Carvalho Chehab { 0x2b, 0xc8 }, /* was 0xcc, new from windrv 090403 */
19270c0d06caSMauro Carvalho Chehab { 0x2c, 0xac },
19280c0d06caSMauro Carvalho Chehab { 0x2d, 0x45 }, /* was 0xd5, new from windrv 090403 */
19290c0d06caSMauro Carvalho Chehab { 0x2e, 0x80 },
19300c0d06caSMauro Carvalho Chehab { 0x2f, 0x14 }, /* was 0x01, new from windrv 090403 */
19310c0d06caSMauro Carvalho Chehab { 0x4c, 0x00 },
19320c0d06caSMauro Carvalho Chehab { 0x4d, 0x30 }, /* was 0x10, new from windrv 090403 */
19330c0d06caSMauro Carvalho Chehab { 0x60, 0x02 }, /* was 0x01, new from windrv 090403 */
19340c0d06caSMauro Carvalho Chehab { 0x61, 0x00 }, /* was 0x09, new from windrv 090403 */
19350c0d06caSMauro Carvalho Chehab { 0x62, 0x5f }, /* was 0xd7, new from windrv 090403 */
19360c0d06caSMauro Carvalho Chehab { 0x63, 0xff },
19370c0d06caSMauro Carvalho Chehab { 0x64, 0x53 }, /* new windrv 090403 says 0x57,
19383e4d8f48SMauro Carvalho Chehab * maybe that's wrong */
19390c0d06caSMauro Carvalho Chehab { 0x65, 0x00 },
19400c0d06caSMauro Carvalho Chehab { 0x66, 0x55 },
19410c0d06caSMauro Carvalho Chehab { 0x67, 0xb0 },
19420c0d06caSMauro Carvalho Chehab { 0x68, 0xc0 }, /* was 0xaf, new from windrv 090403 */
19430c0d06caSMauro Carvalho Chehab { 0x69, 0x02 },
19440c0d06caSMauro Carvalho Chehab { 0x6a, 0x22 },
19450c0d06caSMauro Carvalho Chehab { 0x6b, 0x00 },
19460c0d06caSMauro Carvalho Chehab { 0x6c, 0x99 }, /* was 0x80, old windrv says 0x00, but
19470c0d06caSMauro Carvalho Chehab * deleting bit7 colors the first images red */
19480c0d06caSMauro Carvalho Chehab { 0x6d, 0x11 }, /* was 0x00, new from windrv 090403 */
19490c0d06caSMauro Carvalho Chehab { 0x6e, 0x11 }, /* was 0x00, new from windrv 090403 */
19500c0d06caSMauro Carvalho Chehab { 0x6f, 0x01 },
19510c0d06caSMauro Carvalho Chehab { 0x70, 0x8b },
19520c0d06caSMauro Carvalho Chehab { 0x71, 0x00 },
19530c0d06caSMauro Carvalho Chehab { 0x72, 0x14 },
19540c0d06caSMauro Carvalho Chehab { 0x73, 0x54 },
19550c0d06caSMauro Carvalho Chehab { 0x74, 0x00 },/* 0x60? - was 0x00, new from windrv 090403 */
19560c0d06caSMauro Carvalho Chehab { 0x75, 0x0e },
19570c0d06caSMauro Carvalho Chehab { 0x76, 0x02 }, /* was 0x02, new from windrv 090403 */
19580c0d06caSMauro Carvalho Chehab { 0x77, 0xff },
19590c0d06caSMauro Carvalho Chehab { 0x78, 0x80 },
19600c0d06caSMauro Carvalho Chehab { 0x79, 0x80 },
19610c0d06caSMauro Carvalho Chehab { 0x7a, 0x80 },
19620c0d06caSMauro Carvalho Chehab { 0x7b, 0x10 }, /* was 0x13, new from windrv 090403 */
19630c0d06caSMauro Carvalho Chehab { 0x7c, 0x00 },
19640c0d06caSMauro Carvalho Chehab { 0x7d, 0x08 }, /* was 0x09, new from windrv 090403 */
19650c0d06caSMauro Carvalho Chehab { 0x7e, 0x08 }, /* was 0xc0, new from windrv 090403 */
19660c0d06caSMauro Carvalho Chehab { 0x7f, 0xfb },
19670c0d06caSMauro Carvalho Chehab { 0x80, 0x28 },
19680c0d06caSMauro Carvalho Chehab { 0x81, 0x00 },
19690c0d06caSMauro Carvalho Chehab { 0x82, 0x23 },
19700c0d06caSMauro Carvalho Chehab { 0x83, 0x0b },
19710c0d06caSMauro Carvalho Chehab { 0x84, 0x00 },
19720c0d06caSMauro Carvalho Chehab { 0x85, 0x62 }, /* was 0x61, new from windrv 090403 */
19730c0d06caSMauro Carvalho Chehab { 0x86, 0xc9 },
19740c0d06caSMauro Carvalho Chehab { 0x87, 0x00 },
19750c0d06caSMauro Carvalho Chehab { 0x88, 0x00 },
19760c0d06caSMauro Carvalho Chehab { 0x89, 0x01 },
19770c0d06caSMauro Carvalho Chehab { 0x12, 0x20 },
19780c0d06caSMauro Carvalho Chehab { 0x12, 0x25 }, /* was 0x24, new from windrv 090403 */
19790c0d06caSMauro Carvalho Chehab };
19800c0d06caSMauro Carvalho Chehab
ov7670_abs_to_sm(unsigned char v)19810c0d06caSMauro Carvalho Chehab static unsigned char ov7670_abs_to_sm(unsigned char v)
19820c0d06caSMauro Carvalho Chehab {
19830c0d06caSMauro Carvalho Chehab if (v > 127)
19840c0d06caSMauro Carvalho Chehab return v & 0x7f;
19850c0d06caSMauro Carvalho Chehab return (128 - v) | 0x80;
19860c0d06caSMauro Carvalho Chehab }
19870c0d06caSMauro Carvalho Chehab
19880c0d06caSMauro Carvalho Chehab /* Write a OV519 register */
reg_w(struct sd * sd,u16 index,u16 value)19890c0d06caSMauro Carvalho Chehab static void reg_w(struct sd *sd, u16 index, u16 value)
19900c0d06caSMauro Carvalho Chehab {
1991c93396e1STheodore Kilgore struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
19920c0d06caSMauro Carvalho Chehab int ret, req = 0;
19930c0d06caSMauro Carvalho Chehab
19940c0d06caSMauro Carvalho Chehab if (sd->gspca_dev.usb_err < 0)
19950c0d06caSMauro Carvalho Chehab return;
19960c0d06caSMauro Carvalho Chehab
1997f7c7ac48SWesley Post /* Avoid things going to fast for the bridge with a xhci host */
1998f7c7ac48SWesley Post udelay(150);
1999f7c7ac48SWesley Post
20000c0d06caSMauro Carvalho Chehab switch (sd->bridge) {
20010c0d06caSMauro Carvalho Chehab case BRIDGE_OV511:
20020c0d06caSMauro Carvalho Chehab case BRIDGE_OV511PLUS:
20030c0d06caSMauro Carvalho Chehab req = 2;
20040c0d06caSMauro Carvalho Chehab break;
20050c0d06caSMauro Carvalho Chehab case BRIDGE_OVFX2:
20060c0d06caSMauro Carvalho Chehab req = 0x0a;
20071771e9fbSGustavo A. R. Silva fallthrough;
20080c0d06caSMauro Carvalho Chehab case BRIDGE_W9968CF:
200937d5efb0SJoe Perches gspca_dbg(gspca_dev, D_USBO, "SET %02x %04x %04x\n",
20100c0d06caSMauro Carvalho Chehab req, value, index);
20110c0d06caSMauro Carvalho Chehab ret = usb_control_msg(sd->gspca_dev.dev,
20120c0d06caSMauro Carvalho Chehab usb_sndctrlpipe(sd->gspca_dev.dev, 0),
20130c0d06caSMauro Carvalho Chehab req,
20140c0d06caSMauro Carvalho Chehab USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
20150c0d06caSMauro Carvalho Chehab value, index, NULL, 0, 500);
20160c0d06caSMauro Carvalho Chehab goto leave;
20170c0d06caSMauro Carvalho Chehab default:
20180c0d06caSMauro Carvalho Chehab req = 1;
20190c0d06caSMauro Carvalho Chehab }
20200c0d06caSMauro Carvalho Chehab
202137d5efb0SJoe Perches gspca_dbg(gspca_dev, D_USBO, "SET %02x 0000 %04x %02x\n",
20220c0d06caSMauro Carvalho Chehab req, index, value);
20230c0d06caSMauro Carvalho Chehab sd->gspca_dev.usb_buf[0] = value;
20240c0d06caSMauro Carvalho Chehab ret = usb_control_msg(sd->gspca_dev.dev,
20250c0d06caSMauro Carvalho Chehab usb_sndctrlpipe(sd->gspca_dev.dev, 0),
20260c0d06caSMauro Carvalho Chehab req,
20270c0d06caSMauro Carvalho Chehab USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
20280c0d06caSMauro Carvalho Chehab 0, index,
20290c0d06caSMauro Carvalho Chehab sd->gspca_dev.usb_buf, 1, 500);
20300c0d06caSMauro Carvalho Chehab leave:
20310c0d06caSMauro Carvalho Chehab if (ret < 0) {
203252173c5fSJoe Perches gspca_err(gspca_dev, "reg_w %02x failed %d\n", index, ret);
20330c0d06caSMauro Carvalho Chehab sd->gspca_dev.usb_err = ret;
20340c0d06caSMauro Carvalho Chehab return;
20350c0d06caSMauro Carvalho Chehab }
20360c0d06caSMauro Carvalho Chehab }
20370c0d06caSMauro Carvalho Chehab
20380c0d06caSMauro Carvalho Chehab /* Read from a OV519 register, note not valid for the w9968cf!! */
20390c0d06caSMauro Carvalho Chehab /* returns: negative is error, pos or zero is data */
reg_r(struct sd * sd,u16 index)20400c0d06caSMauro Carvalho Chehab static int reg_r(struct sd *sd, u16 index)
20410c0d06caSMauro Carvalho Chehab {
2042c93396e1STheodore Kilgore struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
20430c0d06caSMauro Carvalho Chehab int ret;
20440c0d06caSMauro Carvalho Chehab int req;
20450c0d06caSMauro Carvalho Chehab
20460c0d06caSMauro Carvalho Chehab if (sd->gspca_dev.usb_err < 0)
20470c0d06caSMauro Carvalho Chehab return -1;
20480c0d06caSMauro Carvalho Chehab
20490c0d06caSMauro Carvalho Chehab switch (sd->bridge) {
20500c0d06caSMauro Carvalho Chehab case BRIDGE_OV511:
20510c0d06caSMauro Carvalho Chehab case BRIDGE_OV511PLUS:
20520c0d06caSMauro Carvalho Chehab req = 3;
20530c0d06caSMauro Carvalho Chehab break;
20540c0d06caSMauro Carvalho Chehab case BRIDGE_OVFX2:
20550c0d06caSMauro Carvalho Chehab req = 0x0b;
20560c0d06caSMauro Carvalho Chehab break;
20570c0d06caSMauro Carvalho Chehab default:
20580c0d06caSMauro Carvalho Chehab req = 1;
20590c0d06caSMauro Carvalho Chehab }
20600c0d06caSMauro Carvalho Chehab
2061f7c7ac48SWesley Post /* Avoid things going to fast for the bridge with a xhci host */
2062f7c7ac48SWesley Post udelay(150);
20630c0d06caSMauro Carvalho Chehab ret = usb_control_msg(sd->gspca_dev.dev,
20640c0d06caSMauro Carvalho Chehab usb_rcvctrlpipe(sd->gspca_dev.dev, 0),
20650c0d06caSMauro Carvalho Chehab req,
20660c0d06caSMauro Carvalho Chehab USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
20670c0d06caSMauro Carvalho Chehab 0, index, sd->gspca_dev.usb_buf, 1, 500);
20680c0d06caSMauro Carvalho Chehab
20690c0d06caSMauro Carvalho Chehab if (ret >= 0) {
20700c0d06caSMauro Carvalho Chehab ret = sd->gspca_dev.usb_buf[0];
207137d5efb0SJoe Perches gspca_dbg(gspca_dev, D_USBI, "GET %02x 0000 %04x %02x\n",
20720c0d06caSMauro Carvalho Chehab req, index, ret);
20730c0d06caSMauro Carvalho Chehab } else {
207452173c5fSJoe Perches gspca_err(gspca_dev, "reg_r %02x failed %d\n", index, ret);
20750c0d06caSMauro Carvalho Chehab sd->gspca_dev.usb_err = ret;
20764843a543SHans Verkuil /*
20774843a543SHans Verkuil * Make sure the result is zeroed to avoid uninitialized
20784843a543SHans Verkuil * values.
20794843a543SHans Verkuil */
20804843a543SHans Verkuil gspca_dev->usb_buf[0] = 0;
20810c0d06caSMauro Carvalho Chehab }
20820c0d06caSMauro Carvalho Chehab
20830c0d06caSMauro Carvalho Chehab return ret;
20840c0d06caSMauro Carvalho Chehab }
20850c0d06caSMauro Carvalho Chehab
20860c0d06caSMauro Carvalho Chehab /* Read 8 values from a OV519 register */
reg_r8(struct sd * sd,u16 index)20870c0d06caSMauro Carvalho Chehab static int reg_r8(struct sd *sd,
20880c0d06caSMauro Carvalho Chehab u16 index)
20890c0d06caSMauro Carvalho Chehab {
2090c93396e1STheodore Kilgore struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
20910c0d06caSMauro Carvalho Chehab int ret;
20920c0d06caSMauro Carvalho Chehab
20930c0d06caSMauro Carvalho Chehab if (sd->gspca_dev.usb_err < 0)
20940c0d06caSMauro Carvalho Chehab return -1;
20950c0d06caSMauro Carvalho Chehab
2096f7c7ac48SWesley Post /* Avoid things going to fast for the bridge with a xhci host */
2097f7c7ac48SWesley Post udelay(150);
20980c0d06caSMauro Carvalho Chehab ret = usb_control_msg(sd->gspca_dev.dev,
20990c0d06caSMauro Carvalho Chehab usb_rcvctrlpipe(sd->gspca_dev.dev, 0),
21000c0d06caSMauro Carvalho Chehab 1, /* REQ_IO */
21010c0d06caSMauro Carvalho Chehab USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
21020c0d06caSMauro Carvalho Chehab 0, index, sd->gspca_dev.usb_buf, 8, 500);
21030c0d06caSMauro Carvalho Chehab
21040c0d06caSMauro Carvalho Chehab if (ret >= 0) {
21050c0d06caSMauro Carvalho Chehab ret = sd->gspca_dev.usb_buf[0];
21060c0d06caSMauro Carvalho Chehab } else {
210752173c5fSJoe Perches gspca_err(gspca_dev, "reg_r8 %02x failed %d\n", index, ret);
21080c0d06caSMauro Carvalho Chehab sd->gspca_dev.usb_err = ret;
21094843a543SHans Verkuil /*
21104843a543SHans Verkuil * Make sure the buffer is zeroed to avoid uninitialized
21114843a543SHans Verkuil * values.
21124843a543SHans Verkuil */
21134843a543SHans Verkuil memset(gspca_dev->usb_buf, 0, 8);
21140c0d06caSMauro Carvalho Chehab }
21150c0d06caSMauro Carvalho Chehab
21160c0d06caSMauro Carvalho Chehab return ret;
21170c0d06caSMauro Carvalho Chehab }
21180c0d06caSMauro Carvalho Chehab
21190c0d06caSMauro Carvalho Chehab /*
21200c0d06caSMauro Carvalho Chehab * Writes bits at positions specified by mask to an OV51x reg. Bits that are in
21210c0d06caSMauro Carvalho Chehab * the same position as 1's in "mask" are cleared and set to "value". Bits
21220c0d06caSMauro Carvalho Chehab * that are in the same position as 0's in "mask" are preserved, regardless
21230c0d06caSMauro Carvalho Chehab * of their respective state in "value".
21240c0d06caSMauro Carvalho Chehab */
reg_w_mask(struct sd * sd,u16 index,u8 value,u8 mask)21250c0d06caSMauro Carvalho Chehab static void reg_w_mask(struct sd *sd,
21260c0d06caSMauro Carvalho Chehab u16 index,
21270c0d06caSMauro Carvalho Chehab u8 value,
21280c0d06caSMauro Carvalho Chehab u8 mask)
21290c0d06caSMauro Carvalho Chehab {
21300c0d06caSMauro Carvalho Chehab int ret;
21310c0d06caSMauro Carvalho Chehab u8 oldval;
21320c0d06caSMauro Carvalho Chehab
21330c0d06caSMauro Carvalho Chehab if (mask != 0xff) {
21340c0d06caSMauro Carvalho Chehab value &= mask; /* Enforce mask on value */
21350c0d06caSMauro Carvalho Chehab ret = reg_r(sd, index);
21360c0d06caSMauro Carvalho Chehab if (ret < 0)
21370c0d06caSMauro Carvalho Chehab return;
21380c0d06caSMauro Carvalho Chehab
21390c0d06caSMauro Carvalho Chehab oldval = ret & ~mask; /* Clear the masked bits */
21400c0d06caSMauro Carvalho Chehab value |= oldval; /* Set the desired bits */
21410c0d06caSMauro Carvalho Chehab }
21420c0d06caSMauro Carvalho Chehab reg_w(sd, index, value);
21430c0d06caSMauro Carvalho Chehab }
21440c0d06caSMauro Carvalho Chehab
21450c0d06caSMauro Carvalho Chehab /*
21460c0d06caSMauro Carvalho Chehab * Writes multiple (n) byte value to a single register. Only valid with certain
21470c0d06caSMauro Carvalho Chehab * registers (0x30 and 0xc4 - 0xce).
21480c0d06caSMauro Carvalho Chehab */
ov518_reg_w32(struct sd * sd,u16 index,u32 value,int n)21490c0d06caSMauro Carvalho Chehab static void ov518_reg_w32(struct sd *sd, u16 index, u32 value, int n)
21500c0d06caSMauro Carvalho Chehab {
2151c93396e1STheodore Kilgore struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
21520c0d06caSMauro Carvalho Chehab int ret;
21530c0d06caSMauro Carvalho Chehab
21540c0d06caSMauro Carvalho Chehab if (sd->gspca_dev.usb_err < 0)
21550c0d06caSMauro Carvalho Chehab return;
21560c0d06caSMauro Carvalho Chehab
21570c0d06caSMauro Carvalho Chehab *((__le32 *) sd->gspca_dev.usb_buf) = __cpu_to_le32(value);
21580c0d06caSMauro Carvalho Chehab
2159f7c7ac48SWesley Post /* Avoid things going to fast for the bridge with a xhci host */
2160f7c7ac48SWesley Post udelay(150);
21610c0d06caSMauro Carvalho Chehab ret = usb_control_msg(sd->gspca_dev.dev,
21620c0d06caSMauro Carvalho Chehab usb_sndctrlpipe(sd->gspca_dev.dev, 0),
21630c0d06caSMauro Carvalho Chehab 1 /* REG_IO */,
21640c0d06caSMauro Carvalho Chehab USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
21650c0d06caSMauro Carvalho Chehab 0, index,
21660c0d06caSMauro Carvalho Chehab sd->gspca_dev.usb_buf, n, 500);
21670c0d06caSMauro Carvalho Chehab if (ret < 0) {
216852173c5fSJoe Perches gspca_err(gspca_dev, "reg_w32 %02x failed %d\n", index, ret);
21690c0d06caSMauro Carvalho Chehab sd->gspca_dev.usb_err = ret;
21700c0d06caSMauro Carvalho Chehab }
21710c0d06caSMauro Carvalho Chehab }
21720c0d06caSMauro Carvalho Chehab
ov511_i2c_w(struct sd * sd,u8 reg,u8 value)21730c0d06caSMauro Carvalho Chehab static void ov511_i2c_w(struct sd *sd, u8 reg, u8 value)
21740c0d06caSMauro Carvalho Chehab {
2175c93396e1STheodore Kilgore struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
21760c0d06caSMauro Carvalho Chehab int rc, retries;
21770c0d06caSMauro Carvalho Chehab
217837d5efb0SJoe Perches gspca_dbg(gspca_dev, D_USBO, "ov511_i2c_w %02x %02x\n", reg, value);
21790c0d06caSMauro Carvalho Chehab
21800c0d06caSMauro Carvalho Chehab /* Three byte write cycle */
21810c0d06caSMauro Carvalho Chehab for (retries = 6; ; ) {
21820c0d06caSMauro Carvalho Chehab /* Select camera register */
21830c0d06caSMauro Carvalho Chehab reg_w(sd, R51x_I2C_SADDR_3, reg);
21840c0d06caSMauro Carvalho Chehab
21850c0d06caSMauro Carvalho Chehab /* Write "value" to I2C data port of OV511 */
21860c0d06caSMauro Carvalho Chehab reg_w(sd, R51x_I2C_DATA, value);
21870c0d06caSMauro Carvalho Chehab
21880c0d06caSMauro Carvalho Chehab /* Initiate 3-byte write cycle */
21890c0d06caSMauro Carvalho Chehab reg_w(sd, R511_I2C_CTL, 0x01);
21900c0d06caSMauro Carvalho Chehab
21910c0d06caSMauro Carvalho Chehab do {
21920c0d06caSMauro Carvalho Chehab rc = reg_r(sd, R511_I2C_CTL);
21930c0d06caSMauro Carvalho Chehab } while (rc > 0 && ((rc & 1) == 0)); /* Retry until idle */
21940c0d06caSMauro Carvalho Chehab
21950c0d06caSMauro Carvalho Chehab if (rc < 0)
21960c0d06caSMauro Carvalho Chehab return;
21970c0d06caSMauro Carvalho Chehab
21980c0d06caSMauro Carvalho Chehab if ((rc & 2) == 0) /* Ack? */
21990c0d06caSMauro Carvalho Chehab break;
22000c0d06caSMauro Carvalho Chehab if (--retries < 0) {
220137d5efb0SJoe Perches gspca_dbg(gspca_dev, D_USBO, "i2c write retries exhausted\n");
22020c0d06caSMauro Carvalho Chehab return;
22030c0d06caSMauro Carvalho Chehab }
22040c0d06caSMauro Carvalho Chehab }
22050c0d06caSMauro Carvalho Chehab }
22060c0d06caSMauro Carvalho Chehab
ov511_i2c_r(struct sd * sd,u8 reg)22070c0d06caSMauro Carvalho Chehab static int ov511_i2c_r(struct sd *sd, u8 reg)
22080c0d06caSMauro Carvalho Chehab {
2209c93396e1STheodore Kilgore struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
22100c0d06caSMauro Carvalho Chehab int rc, value, retries;
22110c0d06caSMauro Carvalho Chehab
22120c0d06caSMauro Carvalho Chehab /* Two byte write cycle */
22130c0d06caSMauro Carvalho Chehab for (retries = 6; ; ) {
22140c0d06caSMauro Carvalho Chehab /* Select camera register */
22150c0d06caSMauro Carvalho Chehab reg_w(sd, R51x_I2C_SADDR_2, reg);
22160c0d06caSMauro Carvalho Chehab
22170c0d06caSMauro Carvalho Chehab /* Initiate 2-byte write cycle */
22180c0d06caSMauro Carvalho Chehab reg_w(sd, R511_I2C_CTL, 0x03);
22190c0d06caSMauro Carvalho Chehab
22200c0d06caSMauro Carvalho Chehab do {
22210c0d06caSMauro Carvalho Chehab rc = reg_r(sd, R511_I2C_CTL);
22220c0d06caSMauro Carvalho Chehab } while (rc > 0 && ((rc & 1) == 0)); /* Retry until idle */
22230c0d06caSMauro Carvalho Chehab
22240c0d06caSMauro Carvalho Chehab if (rc < 0)
22250c0d06caSMauro Carvalho Chehab return rc;
22260c0d06caSMauro Carvalho Chehab
22270c0d06caSMauro Carvalho Chehab if ((rc & 2) == 0) /* Ack? */
22280c0d06caSMauro Carvalho Chehab break;
22290c0d06caSMauro Carvalho Chehab
22300c0d06caSMauro Carvalho Chehab /* I2C abort */
22310c0d06caSMauro Carvalho Chehab reg_w(sd, R511_I2C_CTL, 0x10);
22320c0d06caSMauro Carvalho Chehab
22330c0d06caSMauro Carvalho Chehab if (--retries < 0) {
223437d5efb0SJoe Perches gspca_dbg(gspca_dev, D_USBI, "i2c write retries exhausted\n");
22350c0d06caSMauro Carvalho Chehab return -1;
22360c0d06caSMauro Carvalho Chehab }
22370c0d06caSMauro Carvalho Chehab }
22380c0d06caSMauro Carvalho Chehab
22390c0d06caSMauro Carvalho Chehab /* Two byte read cycle */
22400c0d06caSMauro Carvalho Chehab for (retries = 6; ; ) {
22410c0d06caSMauro Carvalho Chehab /* Initiate 2-byte read cycle */
22420c0d06caSMauro Carvalho Chehab reg_w(sd, R511_I2C_CTL, 0x05);
22430c0d06caSMauro Carvalho Chehab
22440c0d06caSMauro Carvalho Chehab do {
22450c0d06caSMauro Carvalho Chehab rc = reg_r(sd, R511_I2C_CTL);
22460c0d06caSMauro Carvalho Chehab } while (rc > 0 && ((rc & 1) == 0)); /* Retry until idle */
22470c0d06caSMauro Carvalho Chehab
22480c0d06caSMauro Carvalho Chehab if (rc < 0)
22490c0d06caSMauro Carvalho Chehab return rc;
22500c0d06caSMauro Carvalho Chehab
22510c0d06caSMauro Carvalho Chehab if ((rc & 2) == 0) /* Ack? */
22520c0d06caSMauro Carvalho Chehab break;
22530c0d06caSMauro Carvalho Chehab
22540c0d06caSMauro Carvalho Chehab /* I2C abort */
22550c0d06caSMauro Carvalho Chehab reg_w(sd, R511_I2C_CTL, 0x10);
22560c0d06caSMauro Carvalho Chehab
22570c0d06caSMauro Carvalho Chehab if (--retries < 0) {
225837d5efb0SJoe Perches gspca_dbg(gspca_dev, D_USBI, "i2c read retries exhausted\n");
22590c0d06caSMauro Carvalho Chehab return -1;
22600c0d06caSMauro Carvalho Chehab }
22610c0d06caSMauro Carvalho Chehab }
22620c0d06caSMauro Carvalho Chehab
22630c0d06caSMauro Carvalho Chehab value = reg_r(sd, R51x_I2C_DATA);
22640c0d06caSMauro Carvalho Chehab
226537d5efb0SJoe Perches gspca_dbg(gspca_dev, D_USBI, "ov511_i2c_r %02x %02x\n", reg, value);
22660c0d06caSMauro Carvalho Chehab
22670c0d06caSMauro Carvalho Chehab /* This is needed to make i2c_w() work */
22680c0d06caSMauro Carvalho Chehab reg_w(sd, R511_I2C_CTL, 0x05);
22690c0d06caSMauro Carvalho Chehab
22700c0d06caSMauro Carvalho Chehab return value;
22710c0d06caSMauro Carvalho Chehab }
22720c0d06caSMauro Carvalho Chehab
22730c0d06caSMauro Carvalho Chehab /*
22740c0d06caSMauro Carvalho Chehab * The OV518 I2C I/O procedure is different, hence, this function.
22750c0d06caSMauro Carvalho Chehab * This is normally only called from i2c_w(). Note that this function
22760c0d06caSMauro Carvalho Chehab * always succeeds regardless of whether the sensor is present and working.
22770c0d06caSMauro Carvalho Chehab */
ov518_i2c_w(struct sd * sd,u8 reg,u8 value)22780c0d06caSMauro Carvalho Chehab static void ov518_i2c_w(struct sd *sd,
22790c0d06caSMauro Carvalho Chehab u8 reg,
22800c0d06caSMauro Carvalho Chehab u8 value)
22810c0d06caSMauro Carvalho Chehab {
2282c93396e1STheodore Kilgore struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
2283c93396e1STheodore Kilgore
228437d5efb0SJoe Perches gspca_dbg(gspca_dev, D_USBO, "ov518_i2c_w %02x %02x\n", reg, value);
22850c0d06caSMauro Carvalho Chehab
22860c0d06caSMauro Carvalho Chehab /* Select camera register */
22870c0d06caSMauro Carvalho Chehab reg_w(sd, R51x_I2C_SADDR_3, reg);
22880c0d06caSMauro Carvalho Chehab
22890c0d06caSMauro Carvalho Chehab /* Write "value" to I2C data port of OV511 */
22900c0d06caSMauro Carvalho Chehab reg_w(sd, R51x_I2C_DATA, value);
22910c0d06caSMauro Carvalho Chehab
22920c0d06caSMauro Carvalho Chehab /* Initiate 3-byte write cycle */
22930c0d06caSMauro Carvalho Chehab reg_w(sd, R518_I2C_CTL, 0x01);
22940c0d06caSMauro Carvalho Chehab
22950c0d06caSMauro Carvalho Chehab /* wait for write complete */
22960c0d06caSMauro Carvalho Chehab msleep(4);
22970c0d06caSMauro Carvalho Chehab reg_r8(sd, R518_I2C_CTL);
22980c0d06caSMauro Carvalho Chehab }
22990c0d06caSMauro Carvalho Chehab
23000c0d06caSMauro Carvalho Chehab /*
23010c0d06caSMauro Carvalho Chehab * returns: negative is error, pos or zero is data
23020c0d06caSMauro Carvalho Chehab *
23030c0d06caSMauro Carvalho Chehab * The OV518 I2C I/O procedure is different, hence, this function.
23040c0d06caSMauro Carvalho Chehab * This is normally only called from i2c_r(). Note that this function
23050c0d06caSMauro Carvalho Chehab * always succeeds regardless of whether the sensor is present and working.
23060c0d06caSMauro Carvalho Chehab */
ov518_i2c_r(struct sd * sd,u8 reg)23070c0d06caSMauro Carvalho Chehab static int ov518_i2c_r(struct sd *sd, u8 reg)
23080c0d06caSMauro Carvalho Chehab {
2309c93396e1STheodore Kilgore struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
23100c0d06caSMauro Carvalho Chehab int value;
23110c0d06caSMauro Carvalho Chehab
23120c0d06caSMauro Carvalho Chehab /* Select camera register */
23130c0d06caSMauro Carvalho Chehab reg_w(sd, R51x_I2C_SADDR_2, reg);
23140c0d06caSMauro Carvalho Chehab
23150c0d06caSMauro Carvalho Chehab /* Initiate 2-byte write cycle */
23160c0d06caSMauro Carvalho Chehab reg_w(sd, R518_I2C_CTL, 0x03);
23170c0d06caSMauro Carvalho Chehab reg_r8(sd, R518_I2C_CTL);
23180c0d06caSMauro Carvalho Chehab
23190c0d06caSMauro Carvalho Chehab /* Initiate 2-byte read cycle */
23200c0d06caSMauro Carvalho Chehab reg_w(sd, R518_I2C_CTL, 0x05);
23210c0d06caSMauro Carvalho Chehab reg_r8(sd, R518_I2C_CTL);
23220c0d06caSMauro Carvalho Chehab
23230c0d06caSMauro Carvalho Chehab value = reg_r(sd, R51x_I2C_DATA);
232437d5efb0SJoe Perches gspca_dbg(gspca_dev, D_USBI, "ov518_i2c_r %02x %02x\n", reg, value);
23250c0d06caSMauro Carvalho Chehab return value;
23260c0d06caSMauro Carvalho Chehab }
23270c0d06caSMauro Carvalho Chehab
ovfx2_i2c_w(struct sd * sd,u8 reg,u8 value)23280c0d06caSMauro Carvalho Chehab static void ovfx2_i2c_w(struct sd *sd, u8 reg, u8 value)
23290c0d06caSMauro Carvalho Chehab {
2330c93396e1STheodore Kilgore struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
23310c0d06caSMauro Carvalho Chehab int ret;
23320c0d06caSMauro Carvalho Chehab
23330c0d06caSMauro Carvalho Chehab if (sd->gspca_dev.usb_err < 0)
23340c0d06caSMauro Carvalho Chehab return;
23350c0d06caSMauro Carvalho Chehab
23360c0d06caSMauro Carvalho Chehab ret = usb_control_msg(sd->gspca_dev.dev,
23370c0d06caSMauro Carvalho Chehab usb_sndctrlpipe(sd->gspca_dev.dev, 0),
23380c0d06caSMauro Carvalho Chehab 0x02,
23390c0d06caSMauro Carvalho Chehab USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
23400c0d06caSMauro Carvalho Chehab (u16) value, (u16) reg, NULL, 0, 500);
23410c0d06caSMauro Carvalho Chehab
23420c0d06caSMauro Carvalho Chehab if (ret < 0) {
234352173c5fSJoe Perches gspca_err(gspca_dev, "ovfx2_i2c_w %02x failed %d\n", reg, ret);
23440c0d06caSMauro Carvalho Chehab sd->gspca_dev.usb_err = ret;
23450c0d06caSMauro Carvalho Chehab }
23460c0d06caSMauro Carvalho Chehab
234737d5efb0SJoe Perches gspca_dbg(gspca_dev, D_USBO, "ovfx2_i2c_w %02x %02x\n", reg, value);
23480c0d06caSMauro Carvalho Chehab }
23490c0d06caSMauro Carvalho Chehab
ovfx2_i2c_r(struct sd * sd,u8 reg)23500c0d06caSMauro Carvalho Chehab static int ovfx2_i2c_r(struct sd *sd, u8 reg)
23510c0d06caSMauro Carvalho Chehab {
2352c93396e1STheodore Kilgore struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
23530c0d06caSMauro Carvalho Chehab int ret;
23540c0d06caSMauro Carvalho Chehab
23550c0d06caSMauro Carvalho Chehab if (sd->gspca_dev.usb_err < 0)
23560c0d06caSMauro Carvalho Chehab return -1;
23570c0d06caSMauro Carvalho Chehab
23580c0d06caSMauro Carvalho Chehab ret = usb_control_msg(sd->gspca_dev.dev,
23590c0d06caSMauro Carvalho Chehab usb_rcvctrlpipe(sd->gspca_dev.dev, 0),
23600c0d06caSMauro Carvalho Chehab 0x03,
23610c0d06caSMauro Carvalho Chehab USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
23620c0d06caSMauro Carvalho Chehab 0, (u16) reg, sd->gspca_dev.usb_buf, 1, 500);
23630c0d06caSMauro Carvalho Chehab
23640c0d06caSMauro Carvalho Chehab if (ret >= 0) {
23650c0d06caSMauro Carvalho Chehab ret = sd->gspca_dev.usb_buf[0];
236637d5efb0SJoe Perches gspca_dbg(gspca_dev, D_USBI, "ovfx2_i2c_r %02x %02x\n",
236737d5efb0SJoe Perches reg, ret);
23680c0d06caSMauro Carvalho Chehab } else {
236952173c5fSJoe Perches gspca_err(gspca_dev, "ovfx2_i2c_r %02x failed %d\n", reg, ret);
23700c0d06caSMauro Carvalho Chehab sd->gspca_dev.usb_err = ret;
23710c0d06caSMauro Carvalho Chehab }
23720c0d06caSMauro Carvalho Chehab
23730c0d06caSMauro Carvalho Chehab return ret;
23740c0d06caSMauro Carvalho Chehab }
23750c0d06caSMauro Carvalho Chehab
i2c_w(struct sd * sd,u8 reg,u8 value)23760c0d06caSMauro Carvalho Chehab static void i2c_w(struct sd *sd, u8 reg, u8 value)
23770c0d06caSMauro Carvalho Chehab {
23780c0d06caSMauro Carvalho Chehab if (sd->sensor_reg_cache[reg] == value)
23790c0d06caSMauro Carvalho Chehab return;
23800c0d06caSMauro Carvalho Chehab
23810c0d06caSMauro Carvalho Chehab switch (sd->bridge) {
23820c0d06caSMauro Carvalho Chehab case BRIDGE_OV511:
23830c0d06caSMauro Carvalho Chehab case BRIDGE_OV511PLUS:
23840c0d06caSMauro Carvalho Chehab ov511_i2c_w(sd, reg, value);
23850c0d06caSMauro Carvalho Chehab break;
23860c0d06caSMauro Carvalho Chehab case BRIDGE_OV518:
23870c0d06caSMauro Carvalho Chehab case BRIDGE_OV518PLUS:
23880c0d06caSMauro Carvalho Chehab case BRIDGE_OV519:
23890c0d06caSMauro Carvalho Chehab ov518_i2c_w(sd, reg, value);
23900c0d06caSMauro Carvalho Chehab break;
23910c0d06caSMauro Carvalho Chehab case BRIDGE_OVFX2:
23920c0d06caSMauro Carvalho Chehab ovfx2_i2c_w(sd, reg, value);
23930c0d06caSMauro Carvalho Chehab break;
23940c0d06caSMauro Carvalho Chehab case BRIDGE_W9968CF:
23950c0d06caSMauro Carvalho Chehab w9968cf_i2c_w(sd, reg, value);
23960c0d06caSMauro Carvalho Chehab break;
23970c0d06caSMauro Carvalho Chehab }
23980c0d06caSMauro Carvalho Chehab
23990c0d06caSMauro Carvalho Chehab if (sd->gspca_dev.usb_err >= 0) {
24000c0d06caSMauro Carvalho Chehab /* Up on sensor reset empty the register cache */
24010c0d06caSMauro Carvalho Chehab if (reg == 0x12 && (value & 0x80))
24020c0d06caSMauro Carvalho Chehab memset(sd->sensor_reg_cache, -1,
24030c0d06caSMauro Carvalho Chehab sizeof(sd->sensor_reg_cache));
24040c0d06caSMauro Carvalho Chehab else
24050c0d06caSMauro Carvalho Chehab sd->sensor_reg_cache[reg] = value;
24060c0d06caSMauro Carvalho Chehab }
24070c0d06caSMauro Carvalho Chehab }
24080c0d06caSMauro Carvalho Chehab
i2c_r(struct sd * sd,u8 reg)24090c0d06caSMauro Carvalho Chehab static int i2c_r(struct sd *sd, u8 reg)
24100c0d06caSMauro Carvalho Chehab {
24110c0d06caSMauro Carvalho Chehab int ret = -1;
24120c0d06caSMauro Carvalho Chehab
24130c0d06caSMauro Carvalho Chehab if (sd->sensor_reg_cache[reg] != -1)
24140c0d06caSMauro Carvalho Chehab return sd->sensor_reg_cache[reg];
24150c0d06caSMauro Carvalho Chehab
24160c0d06caSMauro Carvalho Chehab switch (sd->bridge) {
24170c0d06caSMauro Carvalho Chehab case BRIDGE_OV511:
24180c0d06caSMauro Carvalho Chehab case BRIDGE_OV511PLUS:
24190c0d06caSMauro Carvalho Chehab ret = ov511_i2c_r(sd, reg);
24200c0d06caSMauro Carvalho Chehab break;
24210c0d06caSMauro Carvalho Chehab case BRIDGE_OV518:
24220c0d06caSMauro Carvalho Chehab case BRIDGE_OV518PLUS:
24230c0d06caSMauro Carvalho Chehab case BRIDGE_OV519:
24240c0d06caSMauro Carvalho Chehab ret = ov518_i2c_r(sd, reg);
24250c0d06caSMauro Carvalho Chehab break;
24260c0d06caSMauro Carvalho Chehab case BRIDGE_OVFX2:
24270c0d06caSMauro Carvalho Chehab ret = ovfx2_i2c_r(sd, reg);
24280c0d06caSMauro Carvalho Chehab break;
24290c0d06caSMauro Carvalho Chehab case BRIDGE_W9968CF:
24300c0d06caSMauro Carvalho Chehab ret = w9968cf_i2c_r(sd, reg);
24310c0d06caSMauro Carvalho Chehab break;
24320c0d06caSMauro Carvalho Chehab }
24330c0d06caSMauro Carvalho Chehab
24340c0d06caSMauro Carvalho Chehab if (ret >= 0)
24350c0d06caSMauro Carvalho Chehab sd->sensor_reg_cache[reg] = ret;
24360c0d06caSMauro Carvalho Chehab
24370c0d06caSMauro Carvalho Chehab return ret;
24380c0d06caSMauro Carvalho Chehab }
24390c0d06caSMauro Carvalho Chehab
24400c0d06caSMauro Carvalho Chehab /* Writes bits at positions specified by mask to an I2C reg. Bits that are in
24410c0d06caSMauro Carvalho Chehab * the same position as 1's in "mask" are cleared and set to "value". Bits
24420c0d06caSMauro Carvalho Chehab * that are in the same position as 0's in "mask" are preserved, regardless
24430c0d06caSMauro Carvalho Chehab * of their respective state in "value".
24440c0d06caSMauro Carvalho Chehab */
i2c_w_mask(struct sd * sd,u8 reg,u8 value,u8 mask)24450c0d06caSMauro Carvalho Chehab static void i2c_w_mask(struct sd *sd,
24460c0d06caSMauro Carvalho Chehab u8 reg,
24470c0d06caSMauro Carvalho Chehab u8 value,
24480c0d06caSMauro Carvalho Chehab u8 mask)
24490c0d06caSMauro Carvalho Chehab {
24500c0d06caSMauro Carvalho Chehab int rc;
24510c0d06caSMauro Carvalho Chehab u8 oldval;
24520c0d06caSMauro Carvalho Chehab
24530c0d06caSMauro Carvalho Chehab value &= mask; /* Enforce mask on value */
24540c0d06caSMauro Carvalho Chehab rc = i2c_r(sd, reg);
24550c0d06caSMauro Carvalho Chehab if (rc < 0)
24560c0d06caSMauro Carvalho Chehab return;
24570c0d06caSMauro Carvalho Chehab oldval = rc & ~mask; /* Clear the masked bits */
24580c0d06caSMauro Carvalho Chehab value |= oldval; /* Set the desired bits */
24590c0d06caSMauro Carvalho Chehab i2c_w(sd, reg, value);
24600c0d06caSMauro Carvalho Chehab }
24610c0d06caSMauro Carvalho Chehab
24620c0d06caSMauro Carvalho Chehab /* Temporarily stops OV511 from functioning. Must do this before changing
24630c0d06caSMauro Carvalho Chehab * registers while the camera is streaming */
ov51x_stop(struct sd * sd)24640c0d06caSMauro Carvalho Chehab static inline void ov51x_stop(struct sd *sd)
24650c0d06caSMauro Carvalho Chehab {
2466c93396e1STheodore Kilgore struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
2467c93396e1STheodore Kilgore
246837d5efb0SJoe Perches gspca_dbg(gspca_dev, D_STREAM, "stopping\n");
24690c0d06caSMauro Carvalho Chehab sd->stopped = 1;
24700c0d06caSMauro Carvalho Chehab switch (sd->bridge) {
24710c0d06caSMauro Carvalho Chehab case BRIDGE_OV511:
24720c0d06caSMauro Carvalho Chehab case BRIDGE_OV511PLUS:
24730c0d06caSMauro Carvalho Chehab reg_w(sd, R51x_SYS_RESET, 0x3d);
24740c0d06caSMauro Carvalho Chehab break;
24750c0d06caSMauro Carvalho Chehab case BRIDGE_OV518:
24760c0d06caSMauro Carvalho Chehab case BRIDGE_OV518PLUS:
24770c0d06caSMauro Carvalho Chehab reg_w_mask(sd, R51x_SYS_RESET, 0x3a, 0x3a);
24780c0d06caSMauro Carvalho Chehab break;
24790c0d06caSMauro Carvalho Chehab case BRIDGE_OV519:
24800c0d06caSMauro Carvalho Chehab reg_w(sd, OV519_R51_RESET1, 0x0f);
24810c0d06caSMauro Carvalho Chehab reg_w(sd, OV519_R51_RESET1, 0x00);
24820c0d06caSMauro Carvalho Chehab reg_w(sd, 0x22, 0x00); /* FRAR */
24830c0d06caSMauro Carvalho Chehab break;
24840c0d06caSMauro Carvalho Chehab case BRIDGE_OVFX2:
24850c0d06caSMauro Carvalho Chehab reg_w_mask(sd, 0x0f, 0x00, 0x02);
24860c0d06caSMauro Carvalho Chehab break;
24870c0d06caSMauro Carvalho Chehab case BRIDGE_W9968CF:
24880c0d06caSMauro Carvalho Chehab reg_w(sd, 0x3c, 0x0a05); /* stop USB transfer */
24890c0d06caSMauro Carvalho Chehab break;
24900c0d06caSMauro Carvalho Chehab }
24910c0d06caSMauro Carvalho Chehab }
24920c0d06caSMauro Carvalho Chehab
24930c0d06caSMauro Carvalho Chehab /* Restarts OV511 after ov511_stop() is called. Has no effect if it is not
24940c0d06caSMauro Carvalho Chehab * actually stopped (for performance). */
ov51x_restart(struct sd * sd)24950c0d06caSMauro Carvalho Chehab static inline void ov51x_restart(struct sd *sd)
24960c0d06caSMauro Carvalho Chehab {
2497c93396e1STheodore Kilgore struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
2498c93396e1STheodore Kilgore
249937d5efb0SJoe Perches gspca_dbg(gspca_dev, D_STREAM, "restarting\n");
25000c0d06caSMauro Carvalho Chehab if (!sd->stopped)
25010c0d06caSMauro Carvalho Chehab return;
25020c0d06caSMauro Carvalho Chehab sd->stopped = 0;
25030c0d06caSMauro Carvalho Chehab
25040c0d06caSMauro Carvalho Chehab /* Reinitialize the stream */
25050c0d06caSMauro Carvalho Chehab switch (sd->bridge) {
25060c0d06caSMauro Carvalho Chehab case BRIDGE_OV511:
25070c0d06caSMauro Carvalho Chehab case BRIDGE_OV511PLUS:
25080c0d06caSMauro Carvalho Chehab reg_w(sd, R51x_SYS_RESET, 0x00);
25090c0d06caSMauro Carvalho Chehab break;
25100c0d06caSMauro Carvalho Chehab case BRIDGE_OV518:
25110c0d06caSMauro Carvalho Chehab case BRIDGE_OV518PLUS:
25120c0d06caSMauro Carvalho Chehab reg_w(sd, 0x2f, 0x80);
25130c0d06caSMauro Carvalho Chehab reg_w(sd, R51x_SYS_RESET, 0x00);
25140c0d06caSMauro Carvalho Chehab break;
25150c0d06caSMauro Carvalho Chehab case BRIDGE_OV519:
25160c0d06caSMauro Carvalho Chehab reg_w(sd, OV519_R51_RESET1, 0x0f);
25170c0d06caSMauro Carvalho Chehab reg_w(sd, OV519_R51_RESET1, 0x00);
25180c0d06caSMauro Carvalho Chehab reg_w(sd, 0x22, 0x1d); /* FRAR */
25190c0d06caSMauro Carvalho Chehab break;
25200c0d06caSMauro Carvalho Chehab case BRIDGE_OVFX2:
25210c0d06caSMauro Carvalho Chehab reg_w_mask(sd, 0x0f, 0x02, 0x02);
25220c0d06caSMauro Carvalho Chehab break;
25230c0d06caSMauro Carvalho Chehab case BRIDGE_W9968CF:
25240c0d06caSMauro Carvalho Chehab reg_w(sd, 0x3c, 0x8a05); /* USB FIFO enable */
25250c0d06caSMauro Carvalho Chehab break;
25260c0d06caSMauro Carvalho Chehab }
25270c0d06caSMauro Carvalho Chehab }
25280c0d06caSMauro Carvalho Chehab
25290c0d06caSMauro Carvalho Chehab static void ov51x_set_slave_ids(struct sd *sd, u8 slave);
25300c0d06caSMauro Carvalho Chehab
25310c0d06caSMauro Carvalho Chehab /* This does an initial reset of an OmniVision sensor and ensures that I2C
25320c0d06caSMauro Carvalho Chehab * is synchronized. Returns <0 on failure.
25330c0d06caSMauro Carvalho Chehab */
init_ov_sensor(struct sd * sd,u8 slave)25340c0d06caSMauro Carvalho Chehab static int init_ov_sensor(struct sd *sd, u8 slave)
25350c0d06caSMauro Carvalho Chehab {
25360c0d06caSMauro Carvalho Chehab int i;
2537c93396e1STheodore Kilgore struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
25380c0d06caSMauro Carvalho Chehab
25390c0d06caSMauro Carvalho Chehab ov51x_set_slave_ids(sd, slave);
25400c0d06caSMauro Carvalho Chehab
25410c0d06caSMauro Carvalho Chehab /* Reset the sensor */
25420c0d06caSMauro Carvalho Chehab i2c_w(sd, 0x12, 0x80);
25430c0d06caSMauro Carvalho Chehab
25440c0d06caSMauro Carvalho Chehab /* Wait for it to initialize */
25450c0d06caSMauro Carvalho Chehab msleep(150);
25460c0d06caSMauro Carvalho Chehab
25470c0d06caSMauro Carvalho Chehab for (i = 0; i < i2c_detect_tries; i++) {
25480c0d06caSMauro Carvalho Chehab if (i2c_r(sd, OV7610_REG_ID_HIGH) == 0x7f &&
25490c0d06caSMauro Carvalho Chehab i2c_r(sd, OV7610_REG_ID_LOW) == 0xa2) {
255037d5efb0SJoe Perches gspca_dbg(gspca_dev, D_PROBE, "I2C synced in %d attempt(s)\n",
255137d5efb0SJoe Perches i);
25520c0d06caSMauro Carvalho Chehab return 0;
25530c0d06caSMauro Carvalho Chehab }
25540c0d06caSMauro Carvalho Chehab
25550c0d06caSMauro Carvalho Chehab /* Reset the sensor */
25560c0d06caSMauro Carvalho Chehab i2c_w(sd, 0x12, 0x80);
25570c0d06caSMauro Carvalho Chehab
25580c0d06caSMauro Carvalho Chehab /* Wait for it to initialize */
25590c0d06caSMauro Carvalho Chehab msleep(150);
25600c0d06caSMauro Carvalho Chehab
25610c0d06caSMauro Carvalho Chehab /* Dummy read to sync I2C */
25620c0d06caSMauro Carvalho Chehab if (i2c_r(sd, 0x00) < 0)
25630c0d06caSMauro Carvalho Chehab return -1;
25640c0d06caSMauro Carvalho Chehab }
25650c0d06caSMauro Carvalho Chehab return -1;
25660c0d06caSMauro Carvalho Chehab }
25670c0d06caSMauro Carvalho Chehab
25680c0d06caSMauro Carvalho Chehab /* Set the read and write slave IDs. The "slave" argument is the write slave,
25690c0d06caSMauro Carvalho Chehab * and the read slave will be set to (slave + 1).
25700c0d06caSMauro Carvalho Chehab * This should not be called from outside the i2c I/O functions.
25710c0d06caSMauro Carvalho Chehab * Sets I2C read and write slave IDs. Returns <0 for error
25720c0d06caSMauro Carvalho Chehab */
ov51x_set_slave_ids(struct sd * sd,u8 slave)25730c0d06caSMauro Carvalho Chehab static void ov51x_set_slave_ids(struct sd *sd,
25740c0d06caSMauro Carvalho Chehab u8 slave)
25750c0d06caSMauro Carvalho Chehab {
25760c0d06caSMauro Carvalho Chehab switch (sd->bridge) {
25770c0d06caSMauro Carvalho Chehab case BRIDGE_OVFX2:
25780c0d06caSMauro Carvalho Chehab reg_w(sd, OVFX2_I2C_ADDR, slave);
25790c0d06caSMauro Carvalho Chehab return;
25800c0d06caSMauro Carvalho Chehab case BRIDGE_W9968CF:
25810c0d06caSMauro Carvalho Chehab sd->sensor_addr = slave;
25820c0d06caSMauro Carvalho Chehab return;
25830c0d06caSMauro Carvalho Chehab }
25840c0d06caSMauro Carvalho Chehab
25850c0d06caSMauro Carvalho Chehab reg_w(sd, R51x_I2C_W_SID, slave);
25860c0d06caSMauro Carvalho Chehab reg_w(sd, R51x_I2C_R_SID, slave + 1);
25870c0d06caSMauro Carvalho Chehab }
25880c0d06caSMauro Carvalho Chehab
write_regvals(struct sd * sd,const struct ov_regvals * regvals,int n)25890c0d06caSMauro Carvalho Chehab static void write_regvals(struct sd *sd,
25900c0d06caSMauro Carvalho Chehab const struct ov_regvals *regvals,
25910c0d06caSMauro Carvalho Chehab int n)
25920c0d06caSMauro Carvalho Chehab {
25930c0d06caSMauro Carvalho Chehab while (--n >= 0) {
25940c0d06caSMauro Carvalho Chehab reg_w(sd, regvals->reg, regvals->val);
25950c0d06caSMauro Carvalho Chehab regvals++;
25960c0d06caSMauro Carvalho Chehab }
25970c0d06caSMauro Carvalho Chehab }
25980c0d06caSMauro Carvalho Chehab
write_i2c_regvals(struct sd * sd,const struct ov_i2c_regvals * regvals,int n)25990c0d06caSMauro Carvalho Chehab static void write_i2c_regvals(struct sd *sd,
26000c0d06caSMauro Carvalho Chehab const struct ov_i2c_regvals *regvals,
26010c0d06caSMauro Carvalho Chehab int n)
26020c0d06caSMauro Carvalho Chehab {
26030c0d06caSMauro Carvalho Chehab while (--n >= 0) {
26040c0d06caSMauro Carvalho Chehab i2c_w(sd, regvals->reg, regvals->val);
26050c0d06caSMauro Carvalho Chehab regvals++;
26060c0d06caSMauro Carvalho Chehab }
26070c0d06caSMauro Carvalho Chehab }
26080c0d06caSMauro Carvalho Chehab
26090c0d06caSMauro Carvalho Chehab /****************************************************************************
26100c0d06caSMauro Carvalho Chehab *
26110c0d06caSMauro Carvalho Chehab * OV511 and sensor configuration
26120c0d06caSMauro Carvalho Chehab *
26130c0d06caSMauro Carvalho Chehab ***************************************************************************/
26140c0d06caSMauro Carvalho Chehab
26150c0d06caSMauro Carvalho Chehab /* This initializes the OV2x10 / OV3610 / OV3620 / OV9600 */
ov_hires_configure(struct sd * sd)26160c0d06caSMauro Carvalho Chehab static void ov_hires_configure(struct sd *sd)
26170c0d06caSMauro Carvalho Chehab {
2618c93396e1STheodore Kilgore struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
26190c0d06caSMauro Carvalho Chehab int high, low;
26200c0d06caSMauro Carvalho Chehab
26210c0d06caSMauro Carvalho Chehab if (sd->bridge != BRIDGE_OVFX2) {
262252173c5fSJoe Perches gspca_err(gspca_dev, "error hires sensors only supported with ovfx2\n");
26230c0d06caSMauro Carvalho Chehab return;
26240c0d06caSMauro Carvalho Chehab }
26250c0d06caSMauro Carvalho Chehab
262637d5efb0SJoe Perches gspca_dbg(gspca_dev, D_PROBE, "starting ov hires configuration\n");
26270c0d06caSMauro Carvalho Chehab
26280c0d06caSMauro Carvalho Chehab /* Detect sensor (sub)type */
26290c0d06caSMauro Carvalho Chehab high = i2c_r(sd, 0x0a);
26300c0d06caSMauro Carvalho Chehab low = i2c_r(sd, 0x0b);
26310c0d06caSMauro Carvalho Chehab /* info("%x, %x", high, low); */
26320c0d06caSMauro Carvalho Chehab switch (high) {
26330c0d06caSMauro Carvalho Chehab case 0x96:
26340c0d06caSMauro Carvalho Chehab switch (low) {
26350c0d06caSMauro Carvalho Chehab case 0x40:
263637d5efb0SJoe Perches gspca_dbg(gspca_dev, D_PROBE, "Sensor is a OV2610\n");
26370c0d06caSMauro Carvalho Chehab sd->sensor = SEN_OV2610;
26380c0d06caSMauro Carvalho Chehab return;
26390c0d06caSMauro Carvalho Chehab case 0x41:
264037d5efb0SJoe Perches gspca_dbg(gspca_dev, D_PROBE, "Sensor is a OV2610AE\n");
26410c0d06caSMauro Carvalho Chehab sd->sensor = SEN_OV2610AE;
26420c0d06caSMauro Carvalho Chehab return;
26430c0d06caSMauro Carvalho Chehab case 0xb1:
264437d5efb0SJoe Perches gspca_dbg(gspca_dev, D_PROBE, "Sensor is a OV9600\n");
26450c0d06caSMauro Carvalho Chehab sd->sensor = SEN_OV9600;
26460c0d06caSMauro Carvalho Chehab return;
26470c0d06caSMauro Carvalho Chehab }
26480c0d06caSMauro Carvalho Chehab break;
26490c0d06caSMauro Carvalho Chehab case 0x36:
26500c0d06caSMauro Carvalho Chehab if ((low & 0x0f) == 0x00) {
265137d5efb0SJoe Perches gspca_dbg(gspca_dev, D_PROBE, "Sensor is a OV3610\n");
26520c0d06caSMauro Carvalho Chehab sd->sensor = SEN_OV3610;
26530c0d06caSMauro Carvalho Chehab return;
26540c0d06caSMauro Carvalho Chehab }
26550c0d06caSMauro Carvalho Chehab break;
26560c0d06caSMauro Carvalho Chehab }
265752173c5fSJoe Perches gspca_err(gspca_dev, "Error unknown sensor type: %02x%02x\n",
265852173c5fSJoe Perches high, low);
26590c0d06caSMauro Carvalho Chehab }
26600c0d06caSMauro Carvalho Chehab
26610c0d06caSMauro Carvalho Chehab /* This initializes the OV8110, OV8610 sensor. The OV8110 uses
26620c0d06caSMauro Carvalho Chehab * the same register settings as the OV8610, since they are very similar.
26630c0d06caSMauro Carvalho Chehab */
ov8xx0_configure(struct sd * sd)26640c0d06caSMauro Carvalho Chehab static void ov8xx0_configure(struct sd *sd)
26650c0d06caSMauro Carvalho Chehab {
2666c93396e1STheodore Kilgore struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
26670c0d06caSMauro Carvalho Chehab int rc;
26680c0d06caSMauro Carvalho Chehab
266937d5efb0SJoe Perches gspca_dbg(gspca_dev, D_PROBE, "starting ov8xx0 configuration\n");
26700c0d06caSMauro Carvalho Chehab
26710c0d06caSMauro Carvalho Chehab /* Detect sensor (sub)type */
26720c0d06caSMauro Carvalho Chehab rc = i2c_r(sd, OV7610_REG_COM_I);
26730c0d06caSMauro Carvalho Chehab if (rc < 0) {
267452173c5fSJoe Perches gspca_err(gspca_dev, "Error detecting sensor type\n");
26750c0d06caSMauro Carvalho Chehab return;
26760c0d06caSMauro Carvalho Chehab }
26770c0d06caSMauro Carvalho Chehab if ((rc & 3) == 1)
26780c0d06caSMauro Carvalho Chehab sd->sensor = SEN_OV8610;
26790c0d06caSMauro Carvalho Chehab else
268052173c5fSJoe Perches gspca_err(gspca_dev, "Unknown image sensor version: %d\n",
268152173c5fSJoe Perches rc & 3);
26820c0d06caSMauro Carvalho Chehab }
26830c0d06caSMauro Carvalho Chehab
26840c0d06caSMauro Carvalho Chehab /* This initializes the OV7610, OV7620, or OV76BE sensor. The OV76BE uses
26850c0d06caSMauro Carvalho Chehab * the same register settings as the OV7610, since they are very similar.
26860c0d06caSMauro Carvalho Chehab */
ov7xx0_configure(struct sd * sd)26870c0d06caSMauro Carvalho Chehab static void ov7xx0_configure(struct sd *sd)
26880c0d06caSMauro Carvalho Chehab {
2689c93396e1STheodore Kilgore struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
26900c0d06caSMauro Carvalho Chehab int rc, high, low;
26910c0d06caSMauro Carvalho Chehab
269237d5efb0SJoe Perches gspca_dbg(gspca_dev, D_PROBE, "starting OV7xx0 configuration\n");
26930c0d06caSMauro Carvalho Chehab
26940c0d06caSMauro Carvalho Chehab /* Detect sensor (sub)type */
26950c0d06caSMauro Carvalho Chehab rc = i2c_r(sd, OV7610_REG_COM_I);
26960c0d06caSMauro Carvalho Chehab
26970c0d06caSMauro Carvalho Chehab /* add OV7670 here
26980c0d06caSMauro Carvalho Chehab * it appears to be wrongly detected as a 7610 by default */
26990c0d06caSMauro Carvalho Chehab if (rc < 0) {
270052173c5fSJoe Perches gspca_err(gspca_dev, "Error detecting sensor type\n");
27010c0d06caSMauro Carvalho Chehab return;
27020c0d06caSMauro Carvalho Chehab }
27030c0d06caSMauro Carvalho Chehab if ((rc & 3) == 3) {
27040c0d06caSMauro Carvalho Chehab /* quick hack to make OV7670s work */
27050c0d06caSMauro Carvalho Chehab high = i2c_r(sd, 0x0a);
27060c0d06caSMauro Carvalho Chehab low = i2c_r(sd, 0x0b);
27070c0d06caSMauro Carvalho Chehab /* info("%x, %x", high, low); */
27080c0d06caSMauro Carvalho Chehab if (high == 0x76 && (low & 0xf0) == 0x70) {
270937d5efb0SJoe Perches gspca_dbg(gspca_dev, D_PROBE, "Sensor is an OV76%02x\n",
271037d5efb0SJoe Perches low);
27110c0d06caSMauro Carvalho Chehab sd->sensor = SEN_OV7670;
27120c0d06caSMauro Carvalho Chehab } else {
271337d5efb0SJoe Perches gspca_dbg(gspca_dev, D_PROBE, "Sensor is an OV7610\n");
27140c0d06caSMauro Carvalho Chehab sd->sensor = SEN_OV7610;
27150c0d06caSMauro Carvalho Chehab }
27160c0d06caSMauro Carvalho Chehab } else if ((rc & 3) == 1) {
27170c0d06caSMauro Carvalho Chehab /* I don't know what's different about the 76BE yet. */
27180c0d06caSMauro Carvalho Chehab if (i2c_r(sd, 0x15) & 1) {
271937d5efb0SJoe Perches gspca_dbg(gspca_dev, D_PROBE, "Sensor is an OV7620AE\n");
27200c0d06caSMauro Carvalho Chehab sd->sensor = SEN_OV7620AE;
27210c0d06caSMauro Carvalho Chehab } else {
272237d5efb0SJoe Perches gspca_dbg(gspca_dev, D_PROBE, "Sensor is an OV76BE\n");
27230c0d06caSMauro Carvalho Chehab sd->sensor = SEN_OV76BE;
27240c0d06caSMauro Carvalho Chehab }
27250c0d06caSMauro Carvalho Chehab } else if ((rc & 3) == 0) {
27260c0d06caSMauro Carvalho Chehab /* try to read product id registers */
27270c0d06caSMauro Carvalho Chehab high = i2c_r(sd, 0x0a);
27280c0d06caSMauro Carvalho Chehab if (high < 0) {
272952173c5fSJoe Perches gspca_err(gspca_dev, "Error detecting camera chip PID\n");
27300c0d06caSMauro Carvalho Chehab return;
27310c0d06caSMauro Carvalho Chehab }
27320c0d06caSMauro Carvalho Chehab low = i2c_r(sd, 0x0b);
27330c0d06caSMauro Carvalho Chehab if (low < 0) {
273452173c5fSJoe Perches gspca_err(gspca_dev, "Error detecting camera chip VER\n");
27350c0d06caSMauro Carvalho Chehab return;
27360c0d06caSMauro Carvalho Chehab }
27370c0d06caSMauro Carvalho Chehab if (high == 0x76) {
27380c0d06caSMauro Carvalho Chehab switch (low) {
27390c0d06caSMauro Carvalho Chehab case 0x30:
274052173c5fSJoe Perches gspca_err(gspca_dev, "Sensor is an OV7630/OV7635\n");
274152173c5fSJoe Perches gspca_err(gspca_dev, "7630 is not supported by this driver\n");
27420c0d06caSMauro Carvalho Chehab return;
27430c0d06caSMauro Carvalho Chehab case 0x40:
274437d5efb0SJoe Perches gspca_dbg(gspca_dev, D_PROBE, "Sensor is an OV7645\n");
27450c0d06caSMauro Carvalho Chehab sd->sensor = SEN_OV7640; /* FIXME */
27460c0d06caSMauro Carvalho Chehab break;
27470c0d06caSMauro Carvalho Chehab case 0x45:
274837d5efb0SJoe Perches gspca_dbg(gspca_dev, D_PROBE, "Sensor is an OV7645B\n");
27490c0d06caSMauro Carvalho Chehab sd->sensor = SEN_OV7640; /* FIXME */
27500c0d06caSMauro Carvalho Chehab break;
27510c0d06caSMauro Carvalho Chehab case 0x48:
275237d5efb0SJoe Perches gspca_dbg(gspca_dev, D_PROBE, "Sensor is an OV7648\n");
27530c0d06caSMauro Carvalho Chehab sd->sensor = SEN_OV7648;
27540c0d06caSMauro Carvalho Chehab break;
27550c0d06caSMauro Carvalho Chehab case 0x60:
275637d5efb0SJoe Perches gspca_dbg(gspca_dev, D_PROBE, "Sensor is a OV7660\n");
27570c0d06caSMauro Carvalho Chehab sd->sensor = SEN_OV7660;
27580c0d06caSMauro Carvalho Chehab break;
27590c0d06caSMauro Carvalho Chehab default:
276052173c5fSJoe Perches gspca_err(gspca_dev, "Unknown sensor: 0x76%02x\n",
276152173c5fSJoe Perches low);
27620c0d06caSMauro Carvalho Chehab return;
27630c0d06caSMauro Carvalho Chehab }
27640c0d06caSMauro Carvalho Chehab } else {
276537d5efb0SJoe Perches gspca_dbg(gspca_dev, D_PROBE, "Sensor is an OV7620\n");
27660c0d06caSMauro Carvalho Chehab sd->sensor = SEN_OV7620;
27670c0d06caSMauro Carvalho Chehab }
27680c0d06caSMauro Carvalho Chehab } else {
276952173c5fSJoe Perches gspca_err(gspca_dev, "Unknown image sensor version: %d\n",
277052173c5fSJoe Perches rc & 3);
27710c0d06caSMauro Carvalho Chehab }
27720c0d06caSMauro Carvalho Chehab }
27730c0d06caSMauro Carvalho Chehab
27740c0d06caSMauro Carvalho Chehab /* This initializes the OV6620, OV6630, OV6630AE, or OV6630AF sensor. */
ov6xx0_configure(struct sd * sd)27750c0d06caSMauro Carvalho Chehab static void ov6xx0_configure(struct sd *sd)
27760c0d06caSMauro Carvalho Chehab {
2777c93396e1STheodore Kilgore struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
27780c0d06caSMauro Carvalho Chehab int rc;
2779c93396e1STheodore Kilgore
278037d5efb0SJoe Perches gspca_dbg(gspca_dev, D_PROBE, "starting OV6xx0 configuration\n");
27810c0d06caSMauro Carvalho Chehab
27820c0d06caSMauro Carvalho Chehab /* Detect sensor (sub)type */
27830c0d06caSMauro Carvalho Chehab rc = i2c_r(sd, OV7610_REG_COM_I);
27840c0d06caSMauro Carvalho Chehab if (rc < 0) {
278552173c5fSJoe Perches gspca_err(gspca_dev, "Error detecting sensor type\n");
27860c0d06caSMauro Carvalho Chehab return;
27870c0d06caSMauro Carvalho Chehab }
27880c0d06caSMauro Carvalho Chehab
27890c0d06caSMauro Carvalho Chehab /* Ugh. The first two bits are the version bits, but
27900c0d06caSMauro Carvalho Chehab * the entire register value must be used. I guess OVT
27910c0d06caSMauro Carvalho Chehab * underestimated how many variants they would make. */
27920c0d06caSMauro Carvalho Chehab switch (rc) {
27930c0d06caSMauro Carvalho Chehab case 0x00:
27940c0d06caSMauro Carvalho Chehab sd->sensor = SEN_OV6630;
27950c0d06caSMauro Carvalho Chehab pr_warn("WARNING: Sensor is an OV66308. Your camera may have been misdetected in previous driver versions.\n");
27960c0d06caSMauro Carvalho Chehab break;
27970c0d06caSMauro Carvalho Chehab case 0x01:
27980c0d06caSMauro Carvalho Chehab sd->sensor = SEN_OV6620;
279937d5efb0SJoe Perches gspca_dbg(gspca_dev, D_PROBE, "Sensor is an OV6620\n");
28000c0d06caSMauro Carvalho Chehab break;
28010c0d06caSMauro Carvalho Chehab case 0x02:
28020c0d06caSMauro Carvalho Chehab sd->sensor = SEN_OV6630;
280337d5efb0SJoe Perches gspca_dbg(gspca_dev, D_PROBE, "Sensor is an OV66308AE\n");
28040c0d06caSMauro Carvalho Chehab break;
28050c0d06caSMauro Carvalho Chehab case 0x03:
28060c0d06caSMauro Carvalho Chehab sd->sensor = SEN_OV66308AF;
280737d5efb0SJoe Perches gspca_dbg(gspca_dev, D_PROBE, "Sensor is an OV66308AF\n");
28080c0d06caSMauro Carvalho Chehab break;
28090c0d06caSMauro Carvalho Chehab case 0x90:
28100c0d06caSMauro Carvalho Chehab sd->sensor = SEN_OV6630;
28110c0d06caSMauro Carvalho Chehab pr_warn("WARNING: Sensor is an OV66307. Your camera may have been misdetected in previous driver versions.\n");
28120c0d06caSMauro Carvalho Chehab break;
28130c0d06caSMauro Carvalho Chehab default:
281452173c5fSJoe Perches gspca_err(gspca_dev, "FATAL: Unknown sensor version: 0x%02x\n",
281552173c5fSJoe Perches rc);
28160c0d06caSMauro Carvalho Chehab return;
28170c0d06caSMauro Carvalho Chehab }
28180c0d06caSMauro Carvalho Chehab
28190c0d06caSMauro Carvalho Chehab /* Set sensor-specific vars */
28200c0d06caSMauro Carvalho Chehab sd->sif = 1;
28210c0d06caSMauro Carvalho Chehab }
28220c0d06caSMauro Carvalho Chehab
28230c0d06caSMauro Carvalho Chehab /* Turns on or off the LED. Only has an effect with OV511+/OV518(+)/OV519 */
ov51x_led_control(struct sd * sd,int on)28240c0d06caSMauro Carvalho Chehab static void ov51x_led_control(struct sd *sd, int on)
28250c0d06caSMauro Carvalho Chehab {
28260c0d06caSMauro Carvalho Chehab if (sd->invert_led)
28270c0d06caSMauro Carvalho Chehab on = !on;
28280c0d06caSMauro Carvalho Chehab
28290c0d06caSMauro Carvalho Chehab switch (sd->bridge) {
28300c0d06caSMauro Carvalho Chehab /* OV511 has no LED control */
28310c0d06caSMauro Carvalho Chehab case BRIDGE_OV511PLUS:
28320c0d06caSMauro Carvalho Chehab reg_w(sd, R511_SYS_LED_CTL, on);
28330c0d06caSMauro Carvalho Chehab break;
28340c0d06caSMauro Carvalho Chehab case BRIDGE_OV518:
28350c0d06caSMauro Carvalho Chehab case BRIDGE_OV518PLUS:
28360c0d06caSMauro Carvalho Chehab reg_w_mask(sd, R518_GPIO_OUT, 0x02 * on, 0x02);
28370c0d06caSMauro Carvalho Chehab break;
28380c0d06caSMauro Carvalho Chehab case BRIDGE_OV519:
28390c0d06caSMauro Carvalho Chehab reg_w_mask(sd, OV519_GPIO_DATA_OUT0, on, 1);
28400c0d06caSMauro Carvalho Chehab break;
28410c0d06caSMauro Carvalho Chehab }
28420c0d06caSMauro Carvalho Chehab }
28430c0d06caSMauro Carvalho Chehab
sd_reset_snapshot(struct gspca_dev * gspca_dev)28440c0d06caSMauro Carvalho Chehab static void sd_reset_snapshot(struct gspca_dev *gspca_dev)
28450c0d06caSMauro Carvalho Chehab {
28460c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev;
28470c0d06caSMauro Carvalho Chehab
28480c0d06caSMauro Carvalho Chehab if (!sd->snapshot_needs_reset)
28490c0d06caSMauro Carvalho Chehab return;
28500c0d06caSMauro Carvalho Chehab
28510c0d06caSMauro Carvalho Chehab /* Note it is important that we clear sd->snapshot_needs_reset,
28520c0d06caSMauro Carvalho Chehab before actually clearing the snapshot state in the bridge
28530c0d06caSMauro Carvalho Chehab otherwise we might race with the pkt_scan interrupt handler */
28540c0d06caSMauro Carvalho Chehab sd->snapshot_needs_reset = 0;
28550c0d06caSMauro Carvalho Chehab
28560c0d06caSMauro Carvalho Chehab switch (sd->bridge) {
28570c0d06caSMauro Carvalho Chehab case BRIDGE_OV511:
28580c0d06caSMauro Carvalho Chehab case BRIDGE_OV511PLUS:
28590c0d06caSMauro Carvalho Chehab reg_w(sd, R51x_SYS_SNAP, 0x02);
28600c0d06caSMauro Carvalho Chehab reg_w(sd, R51x_SYS_SNAP, 0x00);
28610c0d06caSMauro Carvalho Chehab break;
28620c0d06caSMauro Carvalho Chehab case BRIDGE_OV518:
28630c0d06caSMauro Carvalho Chehab case BRIDGE_OV518PLUS:
28640c0d06caSMauro Carvalho Chehab reg_w(sd, R51x_SYS_SNAP, 0x02); /* Reset */
28650c0d06caSMauro Carvalho Chehab reg_w(sd, R51x_SYS_SNAP, 0x01); /* Enable */
28660c0d06caSMauro Carvalho Chehab break;
28670c0d06caSMauro Carvalho Chehab case BRIDGE_OV519:
28680c0d06caSMauro Carvalho Chehab reg_w(sd, R51x_SYS_RESET, 0x40);
28690c0d06caSMauro Carvalho Chehab reg_w(sd, R51x_SYS_RESET, 0x00);
28700c0d06caSMauro Carvalho Chehab break;
28710c0d06caSMauro Carvalho Chehab }
28720c0d06caSMauro Carvalho Chehab }
28730c0d06caSMauro Carvalho Chehab
ov51x_upload_quan_tables(struct sd * sd)28740c0d06caSMauro Carvalho Chehab static void ov51x_upload_quan_tables(struct sd *sd)
28750c0d06caSMauro Carvalho Chehab {
287602256520SColin Ian King static const unsigned char yQuanTable511[] = {
28770c0d06caSMauro Carvalho Chehab 0, 1, 1, 2, 2, 3, 3, 4,
28780c0d06caSMauro Carvalho Chehab 1, 1, 1, 2, 2, 3, 4, 4,
28790c0d06caSMauro Carvalho Chehab 1, 1, 2, 2, 3, 4, 4, 4,
28800c0d06caSMauro Carvalho Chehab 2, 2, 2, 3, 4, 4, 4, 4,
28810c0d06caSMauro Carvalho Chehab 2, 2, 3, 4, 4, 5, 5, 5,
28820c0d06caSMauro Carvalho Chehab 3, 3, 4, 4, 5, 5, 5, 5,
28830c0d06caSMauro Carvalho Chehab 3, 4, 4, 4, 5, 5, 5, 5,
28840c0d06caSMauro Carvalho Chehab 4, 4, 4, 4, 5, 5, 5, 5
28850c0d06caSMauro Carvalho Chehab };
28860c0d06caSMauro Carvalho Chehab
288702256520SColin Ian King static const unsigned char uvQuanTable511[] = {
28880c0d06caSMauro Carvalho Chehab 0, 2, 2, 3, 4, 4, 4, 4,
28890c0d06caSMauro Carvalho Chehab 2, 2, 2, 4, 4, 4, 4, 4,
28900c0d06caSMauro Carvalho Chehab 2, 2, 3, 4, 4, 4, 4, 4,
28910c0d06caSMauro Carvalho Chehab 3, 4, 4, 4, 4, 4, 4, 4,
28920c0d06caSMauro Carvalho Chehab 4, 4, 4, 4, 4, 4, 4, 4,
28930c0d06caSMauro Carvalho Chehab 4, 4, 4, 4, 4, 4, 4, 4,
28940c0d06caSMauro Carvalho Chehab 4, 4, 4, 4, 4, 4, 4, 4,
28950c0d06caSMauro Carvalho Chehab 4, 4, 4, 4, 4, 4, 4, 4
28960c0d06caSMauro Carvalho Chehab };
28970c0d06caSMauro Carvalho Chehab
28980c0d06caSMauro Carvalho Chehab /* OV518 quantization tables are 8x4 (instead of 8x8) */
289902256520SColin Ian King static const unsigned char yQuanTable518[] = {
29000c0d06caSMauro Carvalho Chehab 5, 4, 5, 6, 6, 7, 7, 7,
29010c0d06caSMauro Carvalho Chehab 5, 5, 5, 5, 6, 7, 7, 7,
29020c0d06caSMauro Carvalho Chehab 6, 6, 6, 6, 7, 7, 7, 8,
29030c0d06caSMauro Carvalho Chehab 7, 7, 6, 7, 7, 7, 8, 8
29040c0d06caSMauro Carvalho Chehab };
290502256520SColin Ian King static const unsigned char uvQuanTable518[] = {
29060c0d06caSMauro Carvalho Chehab 6, 6, 6, 7, 7, 7, 7, 7,
29070c0d06caSMauro Carvalho Chehab 6, 6, 6, 7, 7, 7, 7, 7,
29080c0d06caSMauro Carvalho Chehab 6, 6, 6, 7, 7, 7, 7, 8,
29090c0d06caSMauro Carvalho Chehab 7, 7, 7, 7, 7, 7, 8, 8
29100c0d06caSMauro Carvalho Chehab };
29110c0d06caSMauro Carvalho Chehab
2912c93396e1STheodore Kilgore struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
29130c0d06caSMauro Carvalho Chehab const unsigned char *pYTable, *pUVTable;
29140c0d06caSMauro Carvalho Chehab unsigned char val0, val1;
29150c0d06caSMauro Carvalho Chehab int i, size, reg = R51x_COMP_LUT_BEGIN;
29160c0d06caSMauro Carvalho Chehab
291737d5efb0SJoe Perches gspca_dbg(gspca_dev, D_PROBE, "Uploading quantization tables\n");
29180c0d06caSMauro Carvalho Chehab
29190c0d06caSMauro Carvalho Chehab if (sd->bridge == BRIDGE_OV511 || sd->bridge == BRIDGE_OV511PLUS) {
29200c0d06caSMauro Carvalho Chehab pYTable = yQuanTable511;
29210c0d06caSMauro Carvalho Chehab pUVTable = uvQuanTable511;
29220c0d06caSMauro Carvalho Chehab size = 32;
29230c0d06caSMauro Carvalho Chehab } else {
29240c0d06caSMauro Carvalho Chehab pYTable = yQuanTable518;
29250c0d06caSMauro Carvalho Chehab pUVTable = uvQuanTable518;
29260c0d06caSMauro Carvalho Chehab size = 16;
29270c0d06caSMauro Carvalho Chehab }
29280c0d06caSMauro Carvalho Chehab
29290c0d06caSMauro Carvalho Chehab for (i = 0; i < size; i++) {
29300c0d06caSMauro Carvalho Chehab val0 = *pYTable++;
29310c0d06caSMauro Carvalho Chehab val1 = *pYTable++;
29320c0d06caSMauro Carvalho Chehab val0 &= 0x0f;
29330c0d06caSMauro Carvalho Chehab val1 &= 0x0f;
29340c0d06caSMauro Carvalho Chehab val0 |= val1 << 4;
29350c0d06caSMauro Carvalho Chehab reg_w(sd, reg, val0);
29360c0d06caSMauro Carvalho Chehab
29370c0d06caSMauro Carvalho Chehab val0 = *pUVTable++;
29380c0d06caSMauro Carvalho Chehab val1 = *pUVTable++;
29390c0d06caSMauro Carvalho Chehab val0 &= 0x0f;
29400c0d06caSMauro Carvalho Chehab val1 &= 0x0f;
29410c0d06caSMauro Carvalho Chehab val0 |= val1 << 4;
29420c0d06caSMauro Carvalho Chehab reg_w(sd, reg + size, val0);
29430c0d06caSMauro Carvalho Chehab
29440c0d06caSMauro Carvalho Chehab reg++;
29450c0d06caSMauro Carvalho Chehab }
29460c0d06caSMauro Carvalho Chehab }
29470c0d06caSMauro Carvalho Chehab
29480c0d06caSMauro Carvalho Chehab /* This initializes the OV511/OV511+ and the sensor */
ov511_configure(struct gspca_dev * gspca_dev)29490c0d06caSMauro Carvalho Chehab static void ov511_configure(struct gspca_dev *gspca_dev)
29500c0d06caSMauro Carvalho Chehab {
29510c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev;
29520c0d06caSMauro Carvalho Chehab
29530c0d06caSMauro Carvalho Chehab /* For 511 and 511+ */
295402256520SColin Ian King static const struct ov_regvals init_511[] = {
29550c0d06caSMauro Carvalho Chehab { R51x_SYS_RESET, 0x7f },
29560c0d06caSMauro Carvalho Chehab { R51x_SYS_INIT, 0x01 },
29570c0d06caSMauro Carvalho Chehab { R51x_SYS_RESET, 0x7f },
29580c0d06caSMauro Carvalho Chehab { R51x_SYS_INIT, 0x01 },
29590c0d06caSMauro Carvalho Chehab { R51x_SYS_RESET, 0x3f },
29600c0d06caSMauro Carvalho Chehab { R51x_SYS_INIT, 0x01 },
29610c0d06caSMauro Carvalho Chehab { R51x_SYS_RESET, 0x3d },
29620c0d06caSMauro Carvalho Chehab };
29630c0d06caSMauro Carvalho Chehab
296402256520SColin Ian King static const struct ov_regvals norm_511[] = {
29650c0d06caSMauro Carvalho Chehab { R511_DRAM_FLOW_CTL, 0x01 },
29660c0d06caSMauro Carvalho Chehab { R51x_SYS_SNAP, 0x00 },
29670c0d06caSMauro Carvalho Chehab { R51x_SYS_SNAP, 0x02 },
29680c0d06caSMauro Carvalho Chehab { R51x_SYS_SNAP, 0x00 },
29690c0d06caSMauro Carvalho Chehab { R511_FIFO_OPTS, 0x1f },
29700c0d06caSMauro Carvalho Chehab { R511_COMP_EN, 0x00 },
29710c0d06caSMauro Carvalho Chehab { R511_COMP_LUT_EN, 0x03 },
29720c0d06caSMauro Carvalho Chehab };
29730c0d06caSMauro Carvalho Chehab
297402256520SColin Ian King static const struct ov_regvals norm_511_p[] = {
29750c0d06caSMauro Carvalho Chehab { R511_DRAM_FLOW_CTL, 0xff },
29760c0d06caSMauro Carvalho Chehab { R51x_SYS_SNAP, 0x00 },
29770c0d06caSMauro Carvalho Chehab { R51x_SYS_SNAP, 0x02 },
29780c0d06caSMauro Carvalho Chehab { R51x_SYS_SNAP, 0x00 },
29790c0d06caSMauro Carvalho Chehab { R511_FIFO_OPTS, 0xff },
29800c0d06caSMauro Carvalho Chehab { R511_COMP_EN, 0x00 },
29810c0d06caSMauro Carvalho Chehab { R511_COMP_LUT_EN, 0x03 },
29820c0d06caSMauro Carvalho Chehab };
29830c0d06caSMauro Carvalho Chehab
298402256520SColin Ian King static const struct ov_regvals compress_511[] = {
29850c0d06caSMauro Carvalho Chehab { 0x70, 0x1f },
29860c0d06caSMauro Carvalho Chehab { 0x71, 0x05 },
29870c0d06caSMauro Carvalho Chehab { 0x72, 0x06 },
29880c0d06caSMauro Carvalho Chehab { 0x73, 0x06 },
29890c0d06caSMauro Carvalho Chehab { 0x74, 0x14 },
29900c0d06caSMauro Carvalho Chehab { 0x75, 0x03 },
29910c0d06caSMauro Carvalho Chehab { 0x76, 0x04 },
29920c0d06caSMauro Carvalho Chehab { 0x77, 0x04 },
29930c0d06caSMauro Carvalho Chehab };
29940c0d06caSMauro Carvalho Chehab
299537d5efb0SJoe Perches gspca_dbg(gspca_dev, D_PROBE, "Device custom id %x\n",
299637d5efb0SJoe Perches reg_r(sd, R51x_SYS_CUST_ID));
29970c0d06caSMauro Carvalho Chehab
29980c0d06caSMauro Carvalho Chehab write_regvals(sd, init_511, ARRAY_SIZE(init_511));
29990c0d06caSMauro Carvalho Chehab
30000c0d06caSMauro Carvalho Chehab switch (sd->bridge) {
30010c0d06caSMauro Carvalho Chehab case BRIDGE_OV511:
30020c0d06caSMauro Carvalho Chehab write_regvals(sd, norm_511, ARRAY_SIZE(norm_511));
30030c0d06caSMauro Carvalho Chehab break;
30040c0d06caSMauro Carvalho Chehab case BRIDGE_OV511PLUS:
30050c0d06caSMauro Carvalho Chehab write_regvals(sd, norm_511_p, ARRAY_SIZE(norm_511_p));
30060c0d06caSMauro Carvalho Chehab break;
30070c0d06caSMauro Carvalho Chehab }
30080c0d06caSMauro Carvalho Chehab
30090c0d06caSMauro Carvalho Chehab /* Init compression */
30100c0d06caSMauro Carvalho Chehab write_regvals(sd, compress_511, ARRAY_SIZE(compress_511));
30110c0d06caSMauro Carvalho Chehab
30120c0d06caSMauro Carvalho Chehab ov51x_upload_quan_tables(sd);
30130c0d06caSMauro Carvalho Chehab }
30140c0d06caSMauro Carvalho Chehab
30150c0d06caSMauro Carvalho Chehab /* This initializes the OV518/OV518+ and the sensor */
ov518_configure(struct gspca_dev * gspca_dev)30160c0d06caSMauro Carvalho Chehab static void ov518_configure(struct gspca_dev *gspca_dev)
30170c0d06caSMauro Carvalho Chehab {
30180c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev;
30190c0d06caSMauro Carvalho Chehab
30200c0d06caSMauro Carvalho Chehab /* For 518 and 518+ */
302102256520SColin Ian King static const struct ov_regvals init_518[] = {
30220c0d06caSMauro Carvalho Chehab { R51x_SYS_RESET, 0x40 },
30230c0d06caSMauro Carvalho Chehab { R51x_SYS_INIT, 0xe1 },
30240c0d06caSMauro Carvalho Chehab { R51x_SYS_RESET, 0x3e },
30250c0d06caSMauro Carvalho Chehab { R51x_SYS_INIT, 0xe1 },
30260c0d06caSMauro Carvalho Chehab { R51x_SYS_RESET, 0x00 },
30270c0d06caSMauro Carvalho Chehab { R51x_SYS_INIT, 0xe1 },
30280c0d06caSMauro Carvalho Chehab { 0x46, 0x00 },
30290c0d06caSMauro Carvalho Chehab { 0x5d, 0x03 },
30300c0d06caSMauro Carvalho Chehab };
30310c0d06caSMauro Carvalho Chehab
303202256520SColin Ian King static const struct ov_regvals norm_518[] = {
30330c0d06caSMauro Carvalho Chehab { R51x_SYS_SNAP, 0x02 }, /* Reset */
30340c0d06caSMauro Carvalho Chehab { R51x_SYS_SNAP, 0x01 }, /* Enable */
30350c0d06caSMauro Carvalho Chehab { 0x31, 0x0f },
30360c0d06caSMauro Carvalho Chehab { 0x5d, 0x03 },
30370c0d06caSMauro Carvalho Chehab { 0x24, 0x9f },
30380c0d06caSMauro Carvalho Chehab { 0x25, 0x90 },
30390c0d06caSMauro Carvalho Chehab { 0x20, 0x00 },
30400c0d06caSMauro Carvalho Chehab { 0x51, 0x04 },
30410c0d06caSMauro Carvalho Chehab { 0x71, 0x19 },
30420c0d06caSMauro Carvalho Chehab { 0x2f, 0x80 },
30430c0d06caSMauro Carvalho Chehab };
30440c0d06caSMauro Carvalho Chehab
304502256520SColin Ian King static const struct ov_regvals norm_518_p[] = {
30460c0d06caSMauro Carvalho Chehab { R51x_SYS_SNAP, 0x02 }, /* Reset */
30470c0d06caSMauro Carvalho Chehab { R51x_SYS_SNAP, 0x01 }, /* Enable */
30480c0d06caSMauro Carvalho Chehab { 0x31, 0x0f },
30490c0d06caSMauro Carvalho Chehab { 0x5d, 0x03 },
30500c0d06caSMauro Carvalho Chehab { 0x24, 0x9f },
30510c0d06caSMauro Carvalho Chehab { 0x25, 0x90 },
30520c0d06caSMauro Carvalho Chehab { 0x20, 0x60 },
30530c0d06caSMauro Carvalho Chehab { 0x51, 0x02 },
30540c0d06caSMauro Carvalho Chehab { 0x71, 0x19 },
30550c0d06caSMauro Carvalho Chehab { 0x40, 0xff },
30560c0d06caSMauro Carvalho Chehab { 0x41, 0x42 },
30570c0d06caSMauro Carvalho Chehab { 0x46, 0x00 },
30580c0d06caSMauro Carvalho Chehab { 0x33, 0x04 },
30590c0d06caSMauro Carvalho Chehab { 0x21, 0x19 },
30600c0d06caSMauro Carvalho Chehab { 0x3f, 0x10 },
30610c0d06caSMauro Carvalho Chehab { 0x2f, 0x80 },
30620c0d06caSMauro Carvalho Chehab };
30630c0d06caSMauro Carvalho Chehab
30640c0d06caSMauro Carvalho Chehab /* First 5 bits of custom ID reg are a revision ID on OV518 */
3065b82180dbSHans de Goede sd->revision = reg_r(sd, R51x_SYS_CUST_ID) & 0x1f;
306637d5efb0SJoe Perches gspca_dbg(gspca_dev, D_PROBE, "Device revision %d\n", sd->revision);
30670c0d06caSMauro Carvalho Chehab
30680c0d06caSMauro Carvalho Chehab write_regvals(sd, init_518, ARRAY_SIZE(init_518));
30690c0d06caSMauro Carvalho Chehab
30700c0d06caSMauro Carvalho Chehab /* Set LED GPIO pin to output mode */
30710c0d06caSMauro Carvalho Chehab reg_w_mask(sd, R518_GPIO_CTL, 0x00, 0x02);
30720c0d06caSMauro Carvalho Chehab
30730c0d06caSMauro Carvalho Chehab switch (sd->bridge) {
30740c0d06caSMauro Carvalho Chehab case BRIDGE_OV518:
30750c0d06caSMauro Carvalho Chehab write_regvals(sd, norm_518, ARRAY_SIZE(norm_518));
30760c0d06caSMauro Carvalho Chehab break;
30770c0d06caSMauro Carvalho Chehab case BRIDGE_OV518PLUS:
30780c0d06caSMauro Carvalho Chehab write_regvals(sd, norm_518_p, ARRAY_SIZE(norm_518_p));
30790c0d06caSMauro Carvalho Chehab break;
30800c0d06caSMauro Carvalho Chehab }
30810c0d06caSMauro Carvalho Chehab
30820c0d06caSMauro Carvalho Chehab ov51x_upload_quan_tables(sd);
30830c0d06caSMauro Carvalho Chehab
30840c0d06caSMauro Carvalho Chehab reg_w(sd, 0x2f, 0x80);
30850c0d06caSMauro Carvalho Chehab }
30860c0d06caSMauro Carvalho Chehab
ov519_configure(struct sd * sd)30870c0d06caSMauro Carvalho Chehab static void ov519_configure(struct sd *sd)
30880c0d06caSMauro Carvalho Chehab {
30890c0d06caSMauro Carvalho Chehab static const struct ov_regvals init_519[] = {
30900c0d06caSMauro Carvalho Chehab { 0x5a, 0x6d }, /* EnableSystem */
30910c0d06caSMauro Carvalho Chehab { 0x53, 0x9b }, /* don't enable the microcontroller */
30920c0d06caSMauro Carvalho Chehab { OV519_R54_EN_CLK1, 0xff }, /* set bit2 to enable jpeg */
30930c0d06caSMauro Carvalho Chehab { 0x5d, 0x03 },
30940c0d06caSMauro Carvalho Chehab { 0x49, 0x01 },
30950c0d06caSMauro Carvalho Chehab { 0x48, 0x00 },
30960c0d06caSMauro Carvalho Chehab /* Set LED pin to output mode. Bit 4 must be cleared or sensor
30970c0d06caSMauro Carvalho Chehab * detection will fail. This deserves further investigation. */
30980c0d06caSMauro Carvalho Chehab { OV519_GPIO_IO_CTRL0, 0xee },
30990c0d06caSMauro Carvalho Chehab { OV519_R51_RESET1, 0x0f },
31000c0d06caSMauro Carvalho Chehab { OV519_R51_RESET1, 0x00 },
31010c0d06caSMauro Carvalho Chehab { 0x22, 0x00 },
31020c0d06caSMauro Carvalho Chehab /* windows reads 0x55 at this point*/
31030c0d06caSMauro Carvalho Chehab };
31040c0d06caSMauro Carvalho Chehab
31050c0d06caSMauro Carvalho Chehab write_regvals(sd, init_519, ARRAY_SIZE(init_519));
31060c0d06caSMauro Carvalho Chehab }
31070c0d06caSMauro Carvalho Chehab
ovfx2_configure(struct sd * sd)31080c0d06caSMauro Carvalho Chehab static void ovfx2_configure(struct sd *sd)
31090c0d06caSMauro Carvalho Chehab {
31100c0d06caSMauro Carvalho Chehab static const struct ov_regvals init_fx2[] = {
31110c0d06caSMauro Carvalho Chehab { 0x00, 0x60 },
31120c0d06caSMauro Carvalho Chehab { 0x02, 0x01 },
31130c0d06caSMauro Carvalho Chehab { 0x0f, 0x1d },
31140c0d06caSMauro Carvalho Chehab { 0xe9, 0x82 },
31150c0d06caSMauro Carvalho Chehab { 0xea, 0xc7 },
31160c0d06caSMauro Carvalho Chehab { 0xeb, 0x10 },
31170c0d06caSMauro Carvalho Chehab { 0xec, 0xf6 },
31180c0d06caSMauro Carvalho Chehab };
31190c0d06caSMauro Carvalho Chehab
31200c0d06caSMauro Carvalho Chehab sd->stopped = 1;
31210c0d06caSMauro Carvalho Chehab
31220c0d06caSMauro Carvalho Chehab write_regvals(sd, init_fx2, ARRAY_SIZE(init_fx2));
31230c0d06caSMauro Carvalho Chehab }
31240c0d06caSMauro Carvalho Chehab
31250c0d06caSMauro Carvalho Chehab /* set the mode */
31260c0d06caSMauro Carvalho Chehab /* This function works for ov7660 only */
ov519_set_mode(struct sd * sd)31270c0d06caSMauro Carvalho Chehab static void ov519_set_mode(struct sd *sd)
31280c0d06caSMauro Carvalho Chehab {
31290c0d06caSMauro Carvalho Chehab static const struct ov_regvals bridge_ov7660[2][10] = {
31300c0d06caSMauro Carvalho Chehab {{0x10, 0x14}, {0x11, 0x1e}, {0x12, 0x00}, {0x13, 0x00},
31310c0d06caSMauro Carvalho Chehab {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x20, 0x0c},
31320c0d06caSMauro Carvalho Chehab {0x25, 0x01}, {0x26, 0x00}},
31330c0d06caSMauro Carvalho Chehab {{0x10, 0x28}, {0x11, 0x3c}, {0x12, 0x00}, {0x13, 0x00},
31340c0d06caSMauro Carvalho Chehab {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x20, 0x0c},
31350c0d06caSMauro Carvalho Chehab {0x25, 0x03}, {0x26, 0x00}}
31360c0d06caSMauro Carvalho Chehab };
31370c0d06caSMauro Carvalho Chehab static const struct ov_i2c_regvals sensor_ov7660[2][3] = {
31380c0d06caSMauro Carvalho Chehab {{0x12, 0x00}, {0x24, 0x00}, {0x0c, 0x0c}},
31390c0d06caSMauro Carvalho Chehab {{0x12, 0x00}, {0x04, 0x00}, {0x0c, 0x00}}
31400c0d06caSMauro Carvalho Chehab };
31410c0d06caSMauro Carvalho Chehab static const struct ov_i2c_regvals sensor_ov7660_2[] = {
31420c0d06caSMauro Carvalho Chehab {OV7670_R17_HSTART, 0x13},
31430c0d06caSMauro Carvalho Chehab {OV7670_R18_HSTOP, 0x01},
31440c0d06caSMauro Carvalho Chehab {OV7670_R32_HREF, 0x92},
31450c0d06caSMauro Carvalho Chehab {OV7670_R19_VSTART, 0x02},
31460c0d06caSMauro Carvalho Chehab {OV7670_R1A_VSTOP, 0x7a},
31470c0d06caSMauro Carvalho Chehab {OV7670_R03_VREF, 0x00},
31480c0d06caSMauro Carvalho Chehab /* {0x33, 0x00}, */
31490c0d06caSMauro Carvalho Chehab /* {0x34, 0x07}, */
31500c0d06caSMauro Carvalho Chehab /* {0x36, 0x00}, */
31510c0d06caSMauro Carvalho Chehab /* {0x6b, 0x0a}, */
31520c0d06caSMauro Carvalho Chehab };
31530c0d06caSMauro Carvalho Chehab
31540c0d06caSMauro Carvalho Chehab write_regvals(sd, bridge_ov7660[sd->gspca_dev.curr_mode],
31550c0d06caSMauro Carvalho Chehab ARRAY_SIZE(bridge_ov7660[0]));
31560c0d06caSMauro Carvalho Chehab write_i2c_regvals(sd, sensor_ov7660[sd->gspca_dev.curr_mode],
31570c0d06caSMauro Carvalho Chehab ARRAY_SIZE(sensor_ov7660[0]));
31580c0d06caSMauro Carvalho Chehab write_i2c_regvals(sd, sensor_ov7660_2,
31590c0d06caSMauro Carvalho Chehab ARRAY_SIZE(sensor_ov7660_2));
31600c0d06caSMauro Carvalho Chehab }
31610c0d06caSMauro Carvalho Chehab
31620c0d06caSMauro Carvalho Chehab /* set the frame rate */
31630c0d06caSMauro Carvalho Chehab /* This function works for sensors ov7640, ov7648 ov7660 and ov7670 only */
ov519_set_fr(struct sd * sd)31640c0d06caSMauro Carvalho Chehab static void ov519_set_fr(struct sd *sd)
31650c0d06caSMauro Carvalho Chehab {
31660c0d06caSMauro Carvalho Chehab int fr;
31670c0d06caSMauro Carvalho Chehab u8 clock;
31680c0d06caSMauro Carvalho Chehab /* frame rate table with indices:
31690c0d06caSMauro Carvalho Chehab * - mode = 0: 320x240, 1: 640x480
31700c0d06caSMauro Carvalho Chehab * - fr rate = 0: 30, 1: 25, 2: 20, 3: 15, 4: 10, 5: 5
31710c0d06caSMauro Carvalho Chehab * - reg = 0: bridge a4, 1: bridge 23, 2: sensor 11 (clock)
31720c0d06caSMauro Carvalho Chehab */
31730c0d06caSMauro Carvalho Chehab static const u8 fr_tb[2][6][3] = {
31740c0d06caSMauro Carvalho Chehab {{0x04, 0xff, 0x00},
31750c0d06caSMauro Carvalho Chehab {0x04, 0x1f, 0x00},
31760c0d06caSMauro Carvalho Chehab {0x04, 0x1b, 0x00},
31770c0d06caSMauro Carvalho Chehab {0x04, 0x15, 0x00},
31780c0d06caSMauro Carvalho Chehab {0x04, 0x09, 0x00},
31790c0d06caSMauro Carvalho Chehab {0x04, 0x01, 0x00}},
31800c0d06caSMauro Carvalho Chehab {{0x0c, 0xff, 0x00},
31810c0d06caSMauro Carvalho Chehab {0x0c, 0x1f, 0x00},
31820c0d06caSMauro Carvalho Chehab {0x0c, 0x1b, 0x00},
31830c0d06caSMauro Carvalho Chehab {0x04, 0xff, 0x01},
31840c0d06caSMauro Carvalho Chehab {0x04, 0x1f, 0x01},
31850c0d06caSMauro Carvalho Chehab {0x04, 0x1b, 0x01}},
31860c0d06caSMauro Carvalho Chehab };
31870c0d06caSMauro Carvalho Chehab
31880c0d06caSMauro Carvalho Chehab if (frame_rate > 0)
31890c0d06caSMauro Carvalho Chehab sd->frame_rate = frame_rate;
31900c0d06caSMauro Carvalho Chehab if (sd->frame_rate >= 30)
31910c0d06caSMauro Carvalho Chehab fr = 0;
31920c0d06caSMauro Carvalho Chehab else if (sd->frame_rate >= 25)
31930c0d06caSMauro Carvalho Chehab fr = 1;
31940c0d06caSMauro Carvalho Chehab else if (sd->frame_rate >= 20)
31950c0d06caSMauro Carvalho Chehab fr = 2;
31960c0d06caSMauro Carvalho Chehab else if (sd->frame_rate >= 15)
31970c0d06caSMauro Carvalho Chehab fr = 3;
31980c0d06caSMauro Carvalho Chehab else if (sd->frame_rate >= 10)
31990c0d06caSMauro Carvalho Chehab fr = 4;
32000c0d06caSMauro Carvalho Chehab else
32010c0d06caSMauro Carvalho Chehab fr = 5;
32020c0d06caSMauro Carvalho Chehab reg_w(sd, 0xa4, fr_tb[sd->gspca_dev.curr_mode][fr][0]);
32030c0d06caSMauro Carvalho Chehab reg_w(sd, 0x23, fr_tb[sd->gspca_dev.curr_mode][fr][1]);
32040c0d06caSMauro Carvalho Chehab clock = fr_tb[sd->gspca_dev.curr_mode][fr][2];
32050c0d06caSMauro Carvalho Chehab if (sd->sensor == SEN_OV7660)
32060c0d06caSMauro Carvalho Chehab clock |= 0x80; /* enable double clock */
32070c0d06caSMauro Carvalho Chehab ov518_i2c_w(sd, OV7670_R11_CLKRC, clock);
32080c0d06caSMauro Carvalho Chehab }
32090c0d06caSMauro Carvalho Chehab
setautogain(struct gspca_dev * gspca_dev,s32 val)32100c0d06caSMauro Carvalho Chehab static void setautogain(struct gspca_dev *gspca_dev, s32 val)
32110c0d06caSMauro Carvalho Chehab {
32120c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev;
32130c0d06caSMauro Carvalho Chehab
32140c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x13, val ? 0x05 : 0x00, 0x05);
32150c0d06caSMauro Carvalho Chehab }
32160c0d06caSMauro Carvalho Chehab
32170c0d06caSMauro Carvalho Chehab /* this function is called at probe time */
sd_config(struct gspca_dev * gspca_dev,const struct usb_device_id * id)32180c0d06caSMauro Carvalho Chehab static int sd_config(struct gspca_dev *gspca_dev,
32190c0d06caSMauro Carvalho Chehab const struct usb_device_id *id)
32200c0d06caSMauro Carvalho Chehab {
32210c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev;
32220c0d06caSMauro Carvalho Chehab struct cam *cam = &gspca_dev->cam;
32230c0d06caSMauro Carvalho Chehab
32240c0d06caSMauro Carvalho Chehab sd->bridge = id->driver_info & BRIDGE_MASK;
32250c0d06caSMauro Carvalho Chehab sd->invert_led = (id->driver_info & BRIDGE_INVERT_LED) != 0;
32260c0d06caSMauro Carvalho Chehab
32270c0d06caSMauro Carvalho Chehab switch (sd->bridge) {
32280c0d06caSMauro Carvalho Chehab case BRIDGE_OV511:
32290c0d06caSMauro Carvalho Chehab case BRIDGE_OV511PLUS:
32300c0d06caSMauro Carvalho Chehab cam->cam_mode = ov511_vga_mode;
32310c0d06caSMauro Carvalho Chehab cam->nmodes = ARRAY_SIZE(ov511_vga_mode);
32320c0d06caSMauro Carvalho Chehab break;
32330c0d06caSMauro Carvalho Chehab case BRIDGE_OV518:
32340c0d06caSMauro Carvalho Chehab case BRIDGE_OV518PLUS:
32350c0d06caSMauro Carvalho Chehab cam->cam_mode = ov518_vga_mode;
32360c0d06caSMauro Carvalho Chehab cam->nmodes = ARRAY_SIZE(ov518_vga_mode);
32370c0d06caSMauro Carvalho Chehab break;
32380c0d06caSMauro Carvalho Chehab case BRIDGE_OV519:
32390c0d06caSMauro Carvalho Chehab cam->cam_mode = ov519_vga_mode;
32400c0d06caSMauro Carvalho Chehab cam->nmodes = ARRAY_SIZE(ov519_vga_mode);
32410c0d06caSMauro Carvalho Chehab break;
32420c0d06caSMauro Carvalho Chehab case BRIDGE_OVFX2:
32430c0d06caSMauro Carvalho Chehab cam->cam_mode = ov519_vga_mode;
32440c0d06caSMauro Carvalho Chehab cam->nmodes = ARRAY_SIZE(ov519_vga_mode);
32450c0d06caSMauro Carvalho Chehab cam->bulk_size = OVFX2_BULK_SIZE;
32460c0d06caSMauro Carvalho Chehab cam->bulk_nurbs = MAX_NURBS;
32470c0d06caSMauro Carvalho Chehab cam->bulk = 1;
32480c0d06caSMauro Carvalho Chehab break;
32490c0d06caSMauro Carvalho Chehab case BRIDGE_W9968CF:
32500c0d06caSMauro Carvalho Chehab cam->cam_mode = w9968cf_vga_mode;
32510c0d06caSMauro Carvalho Chehab cam->nmodes = ARRAY_SIZE(w9968cf_vga_mode);
32520c0d06caSMauro Carvalho Chehab break;
32530c0d06caSMauro Carvalho Chehab }
32540c0d06caSMauro Carvalho Chehab
32550c0d06caSMauro Carvalho Chehab sd->frame_rate = 15;
32560c0d06caSMauro Carvalho Chehab
32570c0d06caSMauro Carvalho Chehab return 0;
32580c0d06caSMauro Carvalho Chehab }
32590c0d06caSMauro Carvalho Chehab
32600c0d06caSMauro Carvalho Chehab /* this function is called at probe and resume time */
sd_init(struct gspca_dev * gspca_dev)32610c0d06caSMauro Carvalho Chehab static int sd_init(struct gspca_dev *gspca_dev)
32620c0d06caSMauro Carvalho Chehab {
32630c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev;
32640c0d06caSMauro Carvalho Chehab struct cam *cam = &gspca_dev->cam;
32650c0d06caSMauro Carvalho Chehab
32660c0d06caSMauro Carvalho Chehab switch (sd->bridge) {
32670c0d06caSMauro Carvalho Chehab case BRIDGE_OV511:
32680c0d06caSMauro Carvalho Chehab case BRIDGE_OV511PLUS:
32690c0d06caSMauro Carvalho Chehab ov511_configure(gspca_dev);
32700c0d06caSMauro Carvalho Chehab break;
32710c0d06caSMauro Carvalho Chehab case BRIDGE_OV518:
32720c0d06caSMauro Carvalho Chehab case BRIDGE_OV518PLUS:
32730c0d06caSMauro Carvalho Chehab ov518_configure(gspca_dev);
32740c0d06caSMauro Carvalho Chehab break;
32750c0d06caSMauro Carvalho Chehab case BRIDGE_OV519:
32760c0d06caSMauro Carvalho Chehab ov519_configure(sd);
32770c0d06caSMauro Carvalho Chehab break;
32780c0d06caSMauro Carvalho Chehab case BRIDGE_OVFX2:
32790c0d06caSMauro Carvalho Chehab ovfx2_configure(sd);
32800c0d06caSMauro Carvalho Chehab break;
32810c0d06caSMauro Carvalho Chehab case BRIDGE_W9968CF:
32820c0d06caSMauro Carvalho Chehab w9968cf_configure(sd);
32830c0d06caSMauro Carvalho Chehab break;
32840c0d06caSMauro Carvalho Chehab }
32850c0d06caSMauro Carvalho Chehab
32860c0d06caSMauro Carvalho Chehab /* The OV519 must be more aggressive about sensor detection since
32870c0d06caSMauro Carvalho Chehab * I2C write will never fail if the sensor is not present. We have
32880c0d06caSMauro Carvalho Chehab * to try to initialize the sensor to detect its presence */
32890c0d06caSMauro Carvalho Chehab sd->sensor = -1;
32900c0d06caSMauro Carvalho Chehab
32910c0d06caSMauro Carvalho Chehab /* Test for 76xx */
32920c0d06caSMauro Carvalho Chehab if (init_ov_sensor(sd, OV7xx0_SID) >= 0) {
32930c0d06caSMauro Carvalho Chehab ov7xx0_configure(sd);
32940c0d06caSMauro Carvalho Chehab
32950c0d06caSMauro Carvalho Chehab /* Test for 6xx0 */
32960c0d06caSMauro Carvalho Chehab } else if (init_ov_sensor(sd, OV6xx0_SID) >= 0) {
32970c0d06caSMauro Carvalho Chehab ov6xx0_configure(sd);
32980c0d06caSMauro Carvalho Chehab
32990c0d06caSMauro Carvalho Chehab /* Test for 8xx0 */
33000c0d06caSMauro Carvalho Chehab } else if (init_ov_sensor(sd, OV8xx0_SID) >= 0) {
33010c0d06caSMauro Carvalho Chehab ov8xx0_configure(sd);
33020c0d06caSMauro Carvalho Chehab
33030c0d06caSMauro Carvalho Chehab /* Test for 3xxx / 2xxx */
33040c0d06caSMauro Carvalho Chehab } else if (init_ov_sensor(sd, OV_HIRES_SID) >= 0) {
33050c0d06caSMauro Carvalho Chehab ov_hires_configure(sd);
33060c0d06caSMauro Carvalho Chehab } else {
330752173c5fSJoe Perches gspca_err(gspca_dev, "Can't determine sensor slave IDs\n");
33080c0d06caSMauro Carvalho Chehab goto error;
33090c0d06caSMauro Carvalho Chehab }
33100c0d06caSMauro Carvalho Chehab
33110c0d06caSMauro Carvalho Chehab if (sd->sensor < 0)
33120c0d06caSMauro Carvalho Chehab goto error;
33130c0d06caSMauro Carvalho Chehab
33140c0d06caSMauro Carvalho Chehab ov51x_led_control(sd, 0); /* turn LED off */
33150c0d06caSMauro Carvalho Chehab
33160c0d06caSMauro Carvalho Chehab switch (sd->bridge) {
33170c0d06caSMauro Carvalho Chehab case BRIDGE_OV511:
33180c0d06caSMauro Carvalho Chehab case BRIDGE_OV511PLUS:
33190c0d06caSMauro Carvalho Chehab if (sd->sif) {
33200c0d06caSMauro Carvalho Chehab cam->cam_mode = ov511_sif_mode;
33210c0d06caSMauro Carvalho Chehab cam->nmodes = ARRAY_SIZE(ov511_sif_mode);
33220c0d06caSMauro Carvalho Chehab }
33230c0d06caSMauro Carvalho Chehab break;
33240c0d06caSMauro Carvalho Chehab case BRIDGE_OV518:
33250c0d06caSMauro Carvalho Chehab case BRIDGE_OV518PLUS:
33260c0d06caSMauro Carvalho Chehab if (sd->sif) {
33270c0d06caSMauro Carvalho Chehab cam->cam_mode = ov518_sif_mode;
33280c0d06caSMauro Carvalho Chehab cam->nmodes = ARRAY_SIZE(ov518_sif_mode);
33290c0d06caSMauro Carvalho Chehab }
33300c0d06caSMauro Carvalho Chehab break;
33310c0d06caSMauro Carvalho Chehab case BRIDGE_OV519:
33320c0d06caSMauro Carvalho Chehab if (sd->sif) {
33330c0d06caSMauro Carvalho Chehab cam->cam_mode = ov519_sif_mode;
33340c0d06caSMauro Carvalho Chehab cam->nmodes = ARRAY_SIZE(ov519_sif_mode);
33350c0d06caSMauro Carvalho Chehab }
33360c0d06caSMauro Carvalho Chehab break;
33370c0d06caSMauro Carvalho Chehab case BRIDGE_OVFX2:
33380c0d06caSMauro Carvalho Chehab switch (sd->sensor) {
33390c0d06caSMauro Carvalho Chehab case SEN_OV2610:
33400c0d06caSMauro Carvalho Chehab case SEN_OV2610AE:
33410c0d06caSMauro Carvalho Chehab cam->cam_mode = ovfx2_ov2610_mode;
33420c0d06caSMauro Carvalho Chehab cam->nmodes = ARRAY_SIZE(ovfx2_ov2610_mode);
33430c0d06caSMauro Carvalho Chehab break;
33440c0d06caSMauro Carvalho Chehab case SEN_OV3610:
33450c0d06caSMauro Carvalho Chehab cam->cam_mode = ovfx2_ov3610_mode;
33460c0d06caSMauro Carvalho Chehab cam->nmodes = ARRAY_SIZE(ovfx2_ov3610_mode);
33470c0d06caSMauro Carvalho Chehab break;
33480c0d06caSMauro Carvalho Chehab case SEN_OV9600:
33490c0d06caSMauro Carvalho Chehab cam->cam_mode = ovfx2_ov9600_mode;
33500c0d06caSMauro Carvalho Chehab cam->nmodes = ARRAY_SIZE(ovfx2_ov9600_mode);
33510c0d06caSMauro Carvalho Chehab break;
33520c0d06caSMauro Carvalho Chehab default:
33530c0d06caSMauro Carvalho Chehab if (sd->sif) {
33540c0d06caSMauro Carvalho Chehab cam->cam_mode = ov519_sif_mode;
33550c0d06caSMauro Carvalho Chehab cam->nmodes = ARRAY_SIZE(ov519_sif_mode);
33560c0d06caSMauro Carvalho Chehab }
33570c0d06caSMauro Carvalho Chehab break;
33580c0d06caSMauro Carvalho Chehab }
33590c0d06caSMauro Carvalho Chehab break;
33600c0d06caSMauro Carvalho Chehab case BRIDGE_W9968CF:
33610c0d06caSMauro Carvalho Chehab if (sd->sif)
33620c0d06caSMauro Carvalho Chehab cam->nmodes = ARRAY_SIZE(w9968cf_vga_mode) - 1;
33630c0d06caSMauro Carvalho Chehab
33640c0d06caSMauro Carvalho Chehab /* w9968cf needs initialisation once the sensor is known */
33650c0d06caSMauro Carvalho Chehab w9968cf_init(sd);
33660c0d06caSMauro Carvalho Chehab break;
33670c0d06caSMauro Carvalho Chehab }
33680c0d06caSMauro Carvalho Chehab
33690c0d06caSMauro Carvalho Chehab /* initialize the sensor */
33700c0d06caSMauro Carvalho Chehab switch (sd->sensor) {
33710c0d06caSMauro Carvalho Chehab case SEN_OV2610:
33720c0d06caSMauro Carvalho Chehab write_i2c_regvals(sd, norm_2610, ARRAY_SIZE(norm_2610));
33730c0d06caSMauro Carvalho Chehab
33740c0d06caSMauro Carvalho Chehab /* Enable autogain, autoexpo, awb, bandfilter */
33750c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x13, 0x27, 0x27);
33760c0d06caSMauro Carvalho Chehab break;
33770c0d06caSMauro Carvalho Chehab case SEN_OV2610AE:
33780c0d06caSMauro Carvalho Chehab write_i2c_regvals(sd, norm_2610ae, ARRAY_SIZE(norm_2610ae));
33790c0d06caSMauro Carvalho Chehab
33800c0d06caSMauro Carvalho Chehab /* enable autoexpo */
33810c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x13, 0x05, 0x05);
33820c0d06caSMauro Carvalho Chehab break;
33830c0d06caSMauro Carvalho Chehab case SEN_OV3610:
33840c0d06caSMauro Carvalho Chehab write_i2c_regvals(sd, norm_3620b, ARRAY_SIZE(norm_3620b));
33850c0d06caSMauro Carvalho Chehab
33860c0d06caSMauro Carvalho Chehab /* Enable autogain, autoexpo, awb, bandfilter */
33870c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x13, 0x27, 0x27);
33880c0d06caSMauro Carvalho Chehab break;
33890c0d06caSMauro Carvalho Chehab case SEN_OV6620:
33900c0d06caSMauro Carvalho Chehab write_i2c_regvals(sd, norm_6x20, ARRAY_SIZE(norm_6x20));
33910c0d06caSMauro Carvalho Chehab break;
33920c0d06caSMauro Carvalho Chehab case SEN_OV6630:
33930c0d06caSMauro Carvalho Chehab case SEN_OV66308AF:
33940c0d06caSMauro Carvalho Chehab write_i2c_regvals(sd, norm_6x30, ARRAY_SIZE(norm_6x30));
33950c0d06caSMauro Carvalho Chehab break;
33960c0d06caSMauro Carvalho Chehab default:
33970c0d06caSMauro Carvalho Chehab /* case SEN_OV7610: */
33980c0d06caSMauro Carvalho Chehab /* case SEN_OV76BE: */
33990c0d06caSMauro Carvalho Chehab write_i2c_regvals(sd, norm_7610, ARRAY_SIZE(norm_7610));
34000c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x0e, 0x00, 0x40);
34010c0d06caSMauro Carvalho Chehab break;
34020c0d06caSMauro Carvalho Chehab case SEN_OV7620:
34030c0d06caSMauro Carvalho Chehab case SEN_OV7620AE:
34040c0d06caSMauro Carvalho Chehab write_i2c_regvals(sd, norm_7620, ARRAY_SIZE(norm_7620));
34050c0d06caSMauro Carvalho Chehab break;
34060c0d06caSMauro Carvalho Chehab case SEN_OV7640:
34070c0d06caSMauro Carvalho Chehab case SEN_OV7648:
34080c0d06caSMauro Carvalho Chehab write_i2c_regvals(sd, norm_7640, ARRAY_SIZE(norm_7640));
34090c0d06caSMauro Carvalho Chehab break;
34100c0d06caSMauro Carvalho Chehab case SEN_OV7660:
34110c0d06caSMauro Carvalho Chehab i2c_w(sd, OV7670_R12_COM7, OV7670_COM7_RESET);
34120c0d06caSMauro Carvalho Chehab msleep(14);
34130c0d06caSMauro Carvalho Chehab reg_w(sd, OV519_R57_SNAPSHOT, 0x23);
34140c0d06caSMauro Carvalho Chehab write_regvals(sd, init_519_ov7660,
34150c0d06caSMauro Carvalho Chehab ARRAY_SIZE(init_519_ov7660));
34160c0d06caSMauro Carvalho Chehab write_i2c_regvals(sd, norm_7660, ARRAY_SIZE(norm_7660));
34170c0d06caSMauro Carvalho Chehab sd->gspca_dev.curr_mode = 1; /* 640x480 */
34180c0d06caSMauro Carvalho Chehab ov519_set_mode(sd);
34190c0d06caSMauro Carvalho Chehab ov519_set_fr(sd);
34200c0d06caSMauro Carvalho Chehab sd_reset_snapshot(gspca_dev);
34210c0d06caSMauro Carvalho Chehab ov51x_restart(sd);
34220c0d06caSMauro Carvalho Chehab ov51x_stop(sd); /* not in win traces */
34230c0d06caSMauro Carvalho Chehab ov51x_led_control(sd, 0);
34240c0d06caSMauro Carvalho Chehab break;
34250c0d06caSMauro Carvalho Chehab case SEN_OV7670:
34260c0d06caSMauro Carvalho Chehab write_i2c_regvals(sd, norm_7670, ARRAY_SIZE(norm_7670));
34270c0d06caSMauro Carvalho Chehab break;
34280c0d06caSMauro Carvalho Chehab case SEN_OV8610:
34290c0d06caSMauro Carvalho Chehab write_i2c_regvals(sd, norm_8610, ARRAY_SIZE(norm_8610));
34300c0d06caSMauro Carvalho Chehab break;
34310c0d06caSMauro Carvalho Chehab case SEN_OV9600:
34320c0d06caSMauro Carvalho Chehab write_i2c_regvals(sd, norm_9600, ARRAY_SIZE(norm_9600));
34330c0d06caSMauro Carvalho Chehab
34340c0d06caSMauro Carvalho Chehab /* enable autoexpo */
34350c0d06caSMauro Carvalho Chehab /* i2c_w_mask(sd, 0x13, 0x05, 0x05); */
34360c0d06caSMauro Carvalho Chehab break;
34370c0d06caSMauro Carvalho Chehab }
34380c0d06caSMauro Carvalho Chehab return gspca_dev->usb_err;
34390c0d06caSMauro Carvalho Chehab error:
344052173c5fSJoe Perches gspca_err(gspca_dev, "OV519 Config failed\n");
34410c0d06caSMauro Carvalho Chehab return -EINVAL;
34420c0d06caSMauro Carvalho Chehab }
34430c0d06caSMauro Carvalho Chehab
34440c0d06caSMauro Carvalho Chehab /* function called at start time before URB creation */
sd_isoc_init(struct gspca_dev * gspca_dev)34450c0d06caSMauro Carvalho Chehab static int sd_isoc_init(struct gspca_dev *gspca_dev)
34460c0d06caSMauro Carvalho Chehab {
34470c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev;
34480c0d06caSMauro Carvalho Chehab
34490c0d06caSMauro Carvalho Chehab switch (sd->bridge) {
34500c0d06caSMauro Carvalho Chehab case BRIDGE_OVFX2:
34511966bc2aSOndrej Zary if (gspca_dev->pixfmt.width != 800)
34520c0d06caSMauro Carvalho Chehab gspca_dev->cam.bulk_size = OVFX2_BULK_SIZE;
34530c0d06caSMauro Carvalho Chehab else
34540c0d06caSMauro Carvalho Chehab gspca_dev->cam.bulk_size = 7 * 4096;
34550c0d06caSMauro Carvalho Chehab break;
34560c0d06caSMauro Carvalho Chehab }
34570c0d06caSMauro Carvalho Chehab return 0;
34580c0d06caSMauro Carvalho Chehab }
34590c0d06caSMauro Carvalho Chehab
34600c0d06caSMauro Carvalho Chehab /* Set up the OV511/OV511+ with the given image parameters.
34610c0d06caSMauro Carvalho Chehab *
34620c0d06caSMauro Carvalho Chehab * Do not put any sensor-specific code in here (including I2C I/O functions)
34630c0d06caSMauro Carvalho Chehab */
ov511_mode_init_regs(struct sd * sd)34640c0d06caSMauro Carvalho Chehab static void ov511_mode_init_regs(struct sd *sd)
34650c0d06caSMauro Carvalho Chehab {
3466c93396e1STheodore Kilgore struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
34670c0d06caSMauro Carvalho Chehab int hsegs, vsegs, packet_size, fps, needed;
34680c0d06caSMauro Carvalho Chehab int interlaced = 0;
34690c0d06caSMauro Carvalho Chehab struct usb_host_interface *alt;
34700c0d06caSMauro Carvalho Chehab struct usb_interface *intf;
34710c0d06caSMauro Carvalho Chehab
34720c0d06caSMauro Carvalho Chehab intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
34730c0d06caSMauro Carvalho Chehab alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
34740c0d06caSMauro Carvalho Chehab if (!alt) {
347552173c5fSJoe Perches gspca_err(gspca_dev, "Couldn't get altsetting\n");
34760c0d06caSMauro Carvalho Chehab sd->gspca_dev.usb_err = -EIO;
34770c0d06caSMauro Carvalho Chehab return;
34780c0d06caSMauro Carvalho Chehab }
34790c0d06caSMauro Carvalho Chehab
348099891234SJohan Hovold if (alt->desc.bNumEndpoints < 1) {
348199891234SJohan Hovold sd->gspca_dev.usb_err = -ENODEV;
348299891234SJohan Hovold return;
348399891234SJohan Hovold }
348499891234SJohan Hovold
34850c0d06caSMauro Carvalho Chehab packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
34860c0d06caSMauro Carvalho Chehab reg_w(sd, R51x_FIFO_PSIZE, packet_size >> 5);
34870c0d06caSMauro Carvalho Chehab
34880c0d06caSMauro Carvalho Chehab reg_w(sd, R511_CAM_UV_EN, 0x01);
34890c0d06caSMauro Carvalho Chehab reg_w(sd, R511_SNAP_UV_EN, 0x01);
34900c0d06caSMauro Carvalho Chehab reg_w(sd, R511_SNAP_OPTS, 0x03);
34910c0d06caSMauro Carvalho Chehab
34920c0d06caSMauro Carvalho Chehab /* Here I'm assuming that snapshot size == image size.
34930c0d06caSMauro Carvalho Chehab * I hope that's always true. --claudio
34940c0d06caSMauro Carvalho Chehab */
34951966bc2aSOndrej Zary hsegs = (sd->gspca_dev.pixfmt.width >> 3) - 1;
34961966bc2aSOndrej Zary vsegs = (sd->gspca_dev.pixfmt.height >> 3) - 1;
34970c0d06caSMauro Carvalho Chehab
34980c0d06caSMauro Carvalho Chehab reg_w(sd, R511_CAM_PXCNT, hsegs);
34990c0d06caSMauro Carvalho Chehab reg_w(sd, R511_CAM_LNCNT, vsegs);
35000c0d06caSMauro Carvalho Chehab reg_w(sd, R511_CAM_PXDIV, 0x00);
35010c0d06caSMauro Carvalho Chehab reg_w(sd, R511_CAM_LNDIV, 0x00);
35020c0d06caSMauro Carvalho Chehab
35030c0d06caSMauro Carvalho Chehab /* YUV420, low pass filter on */
35040c0d06caSMauro Carvalho Chehab reg_w(sd, R511_CAM_OPTS, 0x03);
35050c0d06caSMauro Carvalho Chehab
35060c0d06caSMauro Carvalho Chehab /* Snapshot additions */
35070c0d06caSMauro Carvalho Chehab reg_w(sd, R511_SNAP_PXCNT, hsegs);
35080c0d06caSMauro Carvalho Chehab reg_w(sd, R511_SNAP_LNCNT, vsegs);
35090c0d06caSMauro Carvalho Chehab reg_w(sd, R511_SNAP_PXDIV, 0x00);
35100c0d06caSMauro Carvalho Chehab reg_w(sd, R511_SNAP_LNDIV, 0x00);
35110c0d06caSMauro Carvalho Chehab
35120c0d06caSMauro Carvalho Chehab /******** Set the framerate ********/
35130c0d06caSMauro Carvalho Chehab if (frame_rate > 0)
35140c0d06caSMauro Carvalho Chehab sd->frame_rate = frame_rate;
35150c0d06caSMauro Carvalho Chehab
35160c0d06caSMauro Carvalho Chehab switch (sd->sensor) {
35170c0d06caSMauro Carvalho Chehab case SEN_OV6620:
35180c0d06caSMauro Carvalho Chehab /* No framerate control, doesn't like higher rates yet */
35190c0d06caSMauro Carvalho Chehab sd->clockdiv = 3;
35200c0d06caSMauro Carvalho Chehab break;
35210c0d06caSMauro Carvalho Chehab
35220c0d06caSMauro Carvalho Chehab /* Note once the FIXME's in mode_init_ov_sensor_regs() are fixed
35230c0d06caSMauro Carvalho Chehab for more sensors we need to do this for them too */
35240c0d06caSMauro Carvalho Chehab case SEN_OV7620:
35250c0d06caSMauro Carvalho Chehab case SEN_OV7620AE:
35260c0d06caSMauro Carvalho Chehab case SEN_OV7640:
35270c0d06caSMauro Carvalho Chehab case SEN_OV7648:
35280c0d06caSMauro Carvalho Chehab case SEN_OV76BE:
35291966bc2aSOndrej Zary if (sd->gspca_dev.pixfmt.width == 320)
35300c0d06caSMauro Carvalho Chehab interlaced = 1;
35311771e9fbSGustavo A. R. Silva fallthrough;
35320c0d06caSMauro Carvalho Chehab case SEN_OV6630:
35330c0d06caSMauro Carvalho Chehab case SEN_OV7610:
35340c0d06caSMauro Carvalho Chehab case SEN_OV7670:
35350c0d06caSMauro Carvalho Chehab switch (sd->frame_rate) {
35360c0d06caSMauro Carvalho Chehab case 30:
35370c0d06caSMauro Carvalho Chehab case 25:
35380c0d06caSMauro Carvalho Chehab /* Not enough bandwidth to do 640x480 @ 30 fps */
35391966bc2aSOndrej Zary if (sd->gspca_dev.pixfmt.width != 640) {
35400c0d06caSMauro Carvalho Chehab sd->clockdiv = 0;
35410c0d06caSMauro Carvalho Chehab break;
35420c0d06caSMauro Carvalho Chehab }
354306eeefe8SMauro Carvalho Chehab /* For 640x480 case */
35441771e9fbSGustavo A. R. Silva fallthrough;
35450c0d06caSMauro Carvalho Chehab default:
35460c0d06caSMauro Carvalho Chehab /* case 20: */
35470c0d06caSMauro Carvalho Chehab /* case 15: */
35480c0d06caSMauro Carvalho Chehab sd->clockdiv = 1;
35490c0d06caSMauro Carvalho Chehab break;
35500c0d06caSMauro Carvalho Chehab case 10:
35510c0d06caSMauro Carvalho Chehab sd->clockdiv = 2;
35520c0d06caSMauro Carvalho Chehab break;
35530c0d06caSMauro Carvalho Chehab case 5:
35540c0d06caSMauro Carvalho Chehab sd->clockdiv = 5;
35550c0d06caSMauro Carvalho Chehab break;
35560c0d06caSMauro Carvalho Chehab }
35570c0d06caSMauro Carvalho Chehab if (interlaced) {
35580c0d06caSMauro Carvalho Chehab sd->clockdiv = (sd->clockdiv + 1) * 2 - 1;
35590c0d06caSMauro Carvalho Chehab /* Higher then 10 does not work */
35600c0d06caSMauro Carvalho Chehab if (sd->clockdiv > 10)
35610c0d06caSMauro Carvalho Chehab sd->clockdiv = 10;
35620c0d06caSMauro Carvalho Chehab }
35630c0d06caSMauro Carvalho Chehab break;
35640c0d06caSMauro Carvalho Chehab
35650c0d06caSMauro Carvalho Chehab case SEN_OV8610:
35660c0d06caSMauro Carvalho Chehab /* No framerate control ?? */
35670c0d06caSMauro Carvalho Chehab sd->clockdiv = 0;
35680c0d06caSMauro Carvalho Chehab break;
35690c0d06caSMauro Carvalho Chehab }
35700c0d06caSMauro Carvalho Chehab
35710c0d06caSMauro Carvalho Chehab /* Check if we have enough bandwidth to disable compression */
35720c0d06caSMauro Carvalho Chehab fps = (interlaced ? 60 : 30) / (sd->clockdiv + 1) + 1;
35731966bc2aSOndrej Zary needed = fps * sd->gspca_dev.pixfmt.width *
35741966bc2aSOndrej Zary sd->gspca_dev.pixfmt.height * 3 / 2;
35750c0d06caSMauro Carvalho Chehab /* 1000 isoc packets/sec */
35760c0d06caSMauro Carvalho Chehab if (needed > 1000 * packet_size) {
35770c0d06caSMauro Carvalho Chehab /* Enable Y and UV quantization and compression */
35780c0d06caSMauro Carvalho Chehab reg_w(sd, R511_COMP_EN, 0x07);
35790c0d06caSMauro Carvalho Chehab reg_w(sd, R511_COMP_LUT_EN, 0x03);
35800c0d06caSMauro Carvalho Chehab } else {
35810c0d06caSMauro Carvalho Chehab reg_w(sd, R511_COMP_EN, 0x06);
35820c0d06caSMauro Carvalho Chehab reg_w(sd, R511_COMP_LUT_EN, 0x00);
35830c0d06caSMauro Carvalho Chehab }
35840c0d06caSMauro Carvalho Chehab
35850c0d06caSMauro Carvalho Chehab reg_w(sd, R51x_SYS_RESET, OV511_RESET_OMNICE);
35860c0d06caSMauro Carvalho Chehab reg_w(sd, R51x_SYS_RESET, 0);
35870c0d06caSMauro Carvalho Chehab }
35880c0d06caSMauro Carvalho Chehab
35890c0d06caSMauro Carvalho Chehab /* Sets up the OV518/OV518+ with the given image parameters
35900c0d06caSMauro Carvalho Chehab *
35910c0d06caSMauro Carvalho Chehab * OV518 needs a completely different approach, until we can figure out what
35920c0d06caSMauro Carvalho Chehab * the individual registers do. Also, only 15 FPS is supported now.
35930c0d06caSMauro Carvalho Chehab *
35940c0d06caSMauro Carvalho Chehab * Do not put any sensor-specific code in here (including I2C I/O functions)
35950c0d06caSMauro Carvalho Chehab */
ov518_mode_init_regs(struct sd * sd)35960c0d06caSMauro Carvalho Chehab static void ov518_mode_init_regs(struct sd *sd)
35970c0d06caSMauro Carvalho Chehab {
3598c93396e1STheodore Kilgore struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
35990c0d06caSMauro Carvalho Chehab int hsegs, vsegs, packet_size;
36000c0d06caSMauro Carvalho Chehab struct usb_host_interface *alt;
36010c0d06caSMauro Carvalho Chehab struct usb_interface *intf;
36020c0d06caSMauro Carvalho Chehab
36030c0d06caSMauro Carvalho Chehab intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
36040c0d06caSMauro Carvalho Chehab alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
36050c0d06caSMauro Carvalho Chehab if (!alt) {
360652173c5fSJoe Perches gspca_err(gspca_dev, "Couldn't get altsetting\n");
36070c0d06caSMauro Carvalho Chehab sd->gspca_dev.usb_err = -EIO;
36080c0d06caSMauro Carvalho Chehab return;
36090c0d06caSMauro Carvalho Chehab }
36100c0d06caSMauro Carvalho Chehab
361199891234SJohan Hovold if (alt->desc.bNumEndpoints < 1) {
361299891234SJohan Hovold sd->gspca_dev.usb_err = -ENODEV;
361399891234SJohan Hovold return;
361499891234SJohan Hovold }
361599891234SJohan Hovold
36160c0d06caSMauro Carvalho Chehab packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
36170c0d06caSMauro Carvalho Chehab ov518_reg_w32(sd, R51x_FIFO_PSIZE, packet_size & ~7, 2);
36180c0d06caSMauro Carvalho Chehab
36190c0d06caSMauro Carvalho Chehab /******** Set the mode ********/
36200c0d06caSMauro Carvalho Chehab reg_w(sd, 0x2b, 0);
36210c0d06caSMauro Carvalho Chehab reg_w(sd, 0x2c, 0);
36220c0d06caSMauro Carvalho Chehab reg_w(sd, 0x2d, 0);
36230c0d06caSMauro Carvalho Chehab reg_w(sd, 0x2e, 0);
36240c0d06caSMauro Carvalho Chehab reg_w(sd, 0x3b, 0);
36250c0d06caSMauro Carvalho Chehab reg_w(sd, 0x3c, 0);
36260c0d06caSMauro Carvalho Chehab reg_w(sd, 0x3d, 0);
36270c0d06caSMauro Carvalho Chehab reg_w(sd, 0x3e, 0);
36280c0d06caSMauro Carvalho Chehab
36290c0d06caSMauro Carvalho Chehab if (sd->bridge == BRIDGE_OV518) {
36300c0d06caSMauro Carvalho Chehab /* Set 8-bit (YVYU) input format */
36310c0d06caSMauro Carvalho Chehab reg_w_mask(sd, 0x20, 0x08, 0x08);
36320c0d06caSMauro Carvalho Chehab
36330c0d06caSMauro Carvalho Chehab /* Set 12-bit (4:2:0) output format */
36340c0d06caSMauro Carvalho Chehab reg_w_mask(sd, 0x28, 0x80, 0xf0);
36350c0d06caSMauro Carvalho Chehab reg_w_mask(sd, 0x38, 0x80, 0xf0);
36360c0d06caSMauro Carvalho Chehab } else {
36370c0d06caSMauro Carvalho Chehab reg_w(sd, 0x28, 0x80);
36380c0d06caSMauro Carvalho Chehab reg_w(sd, 0x38, 0x80);
36390c0d06caSMauro Carvalho Chehab }
36400c0d06caSMauro Carvalho Chehab
36411966bc2aSOndrej Zary hsegs = sd->gspca_dev.pixfmt.width / 16;
36421966bc2aSOndrej Zary vsegs = sd->gspca_dev.pixfmt.height / 4;
36430c0d06caSMauro Carvalho Chehab
36440c0d06caSMauro Carvalho Chehab reg_w(sd, 0x29, hsegs);
36450c0d06caSMauro Carvalho Chehab reg_w(sd, 0x2a, vsegs);
36460c0d06caSMauro Carvalho Chehab
36470c0d06caSMauro Carvalho Chehab reg_w(sd, 0x39, hsegs);
36480c0d06caSMauro Carvalho Chehab reg_w(sd, 0x3a, vsegs);
36490c0d06caSMauro Carvalho Chehab
36500c0d06caSMauro Carvalho Chehab /* Windows driver does this here; who knows why */
36510c0d06caSMauro Carvalho Chehab reg_w(sd, 0x2f, 0x80);
36520c0d06caSMauro Carvalho Chehab
36530c0d06caSMauro Carvalho Chehab /******** Set the framerate ********/
3654b82180dbSHans de Goede if (sd->bridge == BRIDGE_OV518PLUS && sd->revision == 0 &&
3655b82180dbSHans de Goede sd->sensor == SEN_OV7620AE)
3656b82180dbSHans de Goede sd->clockdiv = 0;
3657b82180dbSHans de Goede else
36580c0d06caSMauro Carvalho Chehab sd->clockdiv = 1;
36590c0d06caSMauro Carvalho Chehab
36600c0d06caSMauro Carvalho Chehab /* Mode independent, but framerate dependent, regs */
36610c0d06caSMauro Carvalho Chehab /* 0x51: Clock divider; Only works on some cams which use 2 crystals */
36620c0d06caSMauro Carvalho Chehab reg_w(sd, 0x51, 0x04);
36630c0d06caSMauro Carvalho Chehab reg_w(sd, 0x22, 0x18);
36640c0d06caSMauro Carvalho Chehab reg_w(sd, 0x23, 0xff);
36650c0d06caSMauro Carvalho Chehab
36660c0d06caSMauro Carvalho Chehab if (sd->bridge == BRIDGE_OV518PLUS) {
36670c0d06caSMauro Carvalho Chehab switch (sd->sensor) {
36680c0d06caSMauro Carvalho Chehab case SEN_OV7620AE:
3669b82180dbSHans de Goede /*
3670b82180dbSHans de Goede * HdG: 640x480 needs special handling on device
36713e4d8f48SMauro Carvalho Chehab * revision 2, we check for device revision > 0 to
3672b82180dbSHans de Goede * avoid regressions, as we don't know the correct
3673b82180dbSHans de Goede * thing todo for revision 1.
3674b82180dbSHans de Goede *
3675b82180dbSHans de Goede * Also this likely means we don't need to
3676b82180dbSHans de Goede * differentiate between the OV7620 and OV7620AE,
3677b82180dbSHans de Goede * earlier testing hitting this same problem likely
3678b82180dbSHans de Goede * happened to be with revision < 2 cams using an
3679b82180dbSHans de Goede * OV7620 and revision 2 cams using an OV7620AE.
3680b82180dbSHans de Goede */
36811966bc2aSOndrej Zary if (sd->revision > 0 &&
36821966bc2aSOndrej Zary sd->gspca_dev.pixfmt.width == 640) {
36830c0d06caSMauro Carvalho Chehab reg_w(sd, 0x20, 0x60);
36840c0d06caSMauro Carvalho Chehab reg_w(sd, 0x21, 0x1f);
3685b82180dbSHans de Goede } else {
3686b82180dbSHans de Goede reg_w(sd, 0x20, 0x00);
3687b82180dbSHans de Goede reg_w(sd, 0x21, 0x19);
36880c0d06caSMauro Carvalho Chehab }
36890c0d06caSMauro Carvalho Chehab break;
36900c0d06caSMauro Carvalho Chehab case SEN_OV7620:
36910c0d06caSMauro Carvalho Chehab reg_w(sd, 0x20, 0x00);
36920c0d06caSMauro Carvalho Chehab reg_w(sd, 0x21, 0x19);
36930c0d06caSMauro Carvalho Chehab break;
36940c0d06caSMauro Carvalho Chehab default:
36950c0d06caSMauro Carvalho Chehab reg_w(sd, 0x21, 0x19);
36960c0d06caSMauro Carvalho Chehab }
36970c0d06caSMauro Carvalho Chehab } else
36980c0d06caSMauro Carvalho Chehab reg_w(sd, 0x71, 0x17); /* Compression-related? */
36990c0d06caSMauro Carvalho Chehab
37000c0d06caSMauro Carvalho Chehab /* FIXME: Sensor-specific */
37010c0d06caSMauro Carvalho Chehab /* Bit 5 is what matters here. Of course, it is "reserved" */
37020c0d06caSMauro Carvalho Chehab i2c_w(sd, 0x54, 0x23);
37030c0d06caSMauro Carvalho Chehab
37040c0d06caSMauro Carvalho Chehab reg_w(sd, 0x2f, 0x80);
37050c0d06caSMauro Carvalho Chehab
37060c0d06caSMauro Carvalho Chehab if (sd->bridge == BRIDGE_OV518PLUS) {
37070c0d06caSMauro Carvalho Chehab reg_w(sd, 0x24, 0x94);
37080c0d06caSMauro Carvalho Chehab reg_w(sd, 0x25, 0x90);
37090c0d06caSMauro Carvalho Chehab ov518_reg_w32(sd, 0xc4, 400, 2); /* 190h */
37100c0d06caSMauro Carvalho Chehab ov518_reg_w32(sd, 0xc6, 540, 2); /* 21ch */
37110c0d06caSMauro Carvalho Chehab ov518_reg_w32(sd, 0xc7, 540, 2); /* 21ch */
37120c0d06caSMauro Carvalho Chehab ov518_reg_w32(sd, 0xc8, 108, 2); /* 6ch */
37130c0d06caSMauro Carvalho Chehab ov518_reg_w32(sd, 0xca, 131098, 3); /* 2001ah */
37140c0d06caSMauro Carvalho Chehab ov518_reg_w32(sd, 0xcb, 532, 2); /* 214h */
37150c0d06caSMauro Carvalho Chehab ov518_reg_w32(sd, 0xcc, 2400, 2); /* 960h */
37160c0d06caSMauro Carvalho Chehab ov518_reg_w32(sd, 0xcd, 32, 2); /* 20h */
37170c0d06caSMauro Carvalho Chehab ov518_reg_w32(sd, 0xce, 608, 2); /* 260h */
37180c0d06caSMauro Carvalho Chehab } else {
37190c0d06caSMauro Carvalho Chehab reg_w(sd, 0x24, 0x9f);
37200c0d06caSMauro Carvalho Chehab reg_w(sd, 0x25, 0x90);
37210c0d06caSMauro Carvalho Chehab ov518_reg_w32(sd, 0xc4, 400, 2); /* 190h */
37220c0d06caSMauro Carvalho Chehab ov518_reg_w32(sd, 0xc6, 381, 2); /* 17dh */
37230c0d06caSMauro Carvalho Chehab ov518_reg_w32(sd, 0xc7, 381, 2); /* 17dh */
37240c0d06caSMauro Carvalho Chehab ov518_reg_w32(sd, 0xc8, 128, 2); /* 80h */
37250c0d06caSMauro Carvalho Chehab ov518_reg_w32(sd, 0xca, 183331, 3); /* 2cc23h */
37260c0d06caSMauro Carvalho Chehab ov518_reg_w32(sd, 0xcb, 746, 2); /* 2eah */
37270c0d06caSMauro Carvalho Chehab ov518_reg_w32(sd, 0xcc, 1750, 2); /* 6d6h */
37280c0d06caSMauro Carvalho Chehab ov518_reg_w32(sd, 0xcd, 45, 2); /* 2dh */
37290c0d06caSMauro Carvalho Chehab ov518_reg_w32(sd, 0xce, 851, 2); /* 353h */
37300c0d06caSMauro Carvalho Chehab }
37310c0d06caSMauro Carvalho Chehab
37320c0d06caSMauro Carvalho Chehab reg_w(sd, 0x2f, 0x80);
37330c0d06caSMauro Carvalho Chehab }
37340c0d06caSMauro Carvalho Chehab
37350c0d06caSMauro Carvalho Chehab /* Sets up the OV519 with the given image parameters
37360c0d06caSMauro Carvalho Chehab *
37370c0d06caSMauro Carvalho Chehab * OV519 needs a completely different approach, until we can figure out what
37380c0d06caSMauro Carvalho Chehab * the individual registers do.
37390c0d06caSMauro Carvalho Chehab *
37400c0d06caSMauro Carvalho Chehab * Do not put any sensor-specific code in here (including I2C I/O functions)
37410c0d06caSMauro Carvalho Chehab */
ov519_mode_init_regs(struct sd * sd)37420c0d06caSMauro Carvalho Chehab static void ov519_mode_init_regs(struct sd *sd)
37430c0d06caSMauro Carvalho Chehab {
37440c0d06caSMauro Carvalho Chehab static const struct ov_regvals mode_init_519_ov7670[] = {
37450c0d06caSMauro Carvalho Chehab { 0x5d, 0x03 }, /* Turn off suspend mode */
37460c0d06caSMauro Carvalho Chehab { 0x53, 0x9f }, /* was 9b in 1.65-1.08 */
37470c0d06caSMauro Carvalho Chehab { OV519_R54_EN_CLK1, 0x0f }, /* bit2 (jpeg enable) */
37480c0d06caSMauro Carvalho Chehab { 0xa2, 0x20 }, /* a2-a5 are undocumented */
37490c0d06caSMauro Carvalho Chehab { 0xa3, 0x18 },
37500c0d06caSMauro Carvalho Chehab { 0xa4, 0x04 },
37510c0d06caSMauro Carvalho Chehab { 0xa5, 0x28 },
37520c0d06caSMauro Carvalho Chehab { 0x37, 0x00 }, /* SetUsbInit */
37530c0d06caSMauro Carvalho Chehab { 0x55, 0x02 }, /* 4.096 Mhz audio clock */
37540c0d06caSMauro Carvalho Chehab /* Enable both fields, YUV Input, disable defect comp (why?) */
37550c0d06caSMauro Carvalho Chehab { 0x20, 0x0c },
37560c0d06caSMauro Carvalho Chehab { 0x21, 0x38 },
37570c0d06caSMauro Carvalho Chehab { 0x22, 0x1d },
37580c0d06caSMauro Carvalho Chehab { 0x17, 0x50 }, /* undocumented */
37590c0d06caSMauro Carvalho Chehab { 0x37, 0x00 }, /* undocumented */
37600c0d06caSMauro Carvalho Chehab { 0x40, 0xff }, /* I2C timeout counter */
37610c0d06caSMauro Carvalho Chehab { 0x46, 0x00 }, /* I2C clock prescaler */
37620c0d06caSMauro Carvalho Chehab { 0x59, 0x04 }, /* new from windrv 090403 */
37630c0d06caSMauro Carvalho Chehab { 0xff, 0x00 }, /* undocumented */
37640c0d06caSMauro Carvalho Chehab /* windows reads 0x55 at this point, why? */
37650c0d06caSMauro Carvalho Chehab };
37660c0d06caSMauro Carvalho Chehab
37670c0d06caSMauro Carvalho Chehab static const struct ov_regvals mode_init_519[] = {
37680c0d06caSMauro Carvalho Chehab { 0x5d, 0x03 }, /* Turn off suspend mode */
37690c0d06caSMauro Carvalho Chehab { 0x53, 0x9f }, /* was 9b in 1.65-1.08 */
37700c0d06caSMauro Carvalho Chehab { OV519_R54_EN_CLK1, 0x0f }, /* bit2 (jpeg enable) */
37710c0d06caSMauro Carvalho Chehab { 0xa2, 0x20 }, /* a2-a5 are undocumented */
37720c0d06caSMauro Carvalho Chehab { 0xa3, 0x18 },
37730c0d06caSMauro Carvalho Chehab { 0xa4, 0x04 },
37740c0d06caSMauro Carvalho Chehab { 0xa5, 0x28 },
37750c0d06caSMauro Carvalho Chehab { 0x37, 0x00 }, /* SetUsbInit */
37760c0d06caSMauro Carvalho Chehab { 0x55, 0x02 }, /* 4.096 Mhz audio clock */
37770c0d06caSMauro Carvalho Chehab /* Enable both fields, YUV Input, disable defect comp (why?) */
37780c0d06caSMauro Carvalho Chehab { 0x22, 0x1d },
37790c0d06caSMauro Carvalho Chehab { 0x17, 0x50 }, /* undocumented */
37800c0d06caSMauro Carvalho Chehab { 0x37, 0x00 }, /* undocumented */
37810c0d06caSMauro Carvalho Chehab { 0x40, 0xff }, /* I2C timeout counter */
37820c0d06caSMauro Carvalho Chehab { 0x46, 0x00 }, /* I2C clock prescaler */
37830c0d06caSMauro Carvalho Chehab { 0x59, 0x04 }, /* new from windrv 090403 */
37840c0d06caSMauro Carvalho Chehab { 0xff, 0x00 }, /* undocumented */
37850c0d06caSMauro Carvalho Chehab /* windows reads 0x55 at this point, why? */
37860c0d06caSMauro Carvalho Chehab };
37870c0d06caSMauro Carvalho Chehab
3788c93396e1STheodore Kilgore struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
3789c93396e1STheodore Kilgore
37900c0d06caSMauro Carvalho Chehab /******** Set the mode ********/
37910c0d06caSMauro Carvalho Chehab switch (sd->sensor) {
37920c0d06caSMauro Carvalho Chehab default:
37930c0d06caSMauro Carvalho Chehab write_regvals(sd, mode_init_519, ARRAY_SIZE(mode_init_519));
37940c0d06caSMauro Carvalho Chehab if (sd->sensor == SEN_OV7640 ||
37950c0d06caSMauro Carvalho Chehab sd->sensor == SEN_OV7648) {
37960c0d06caSMauro Carvalho Chehab /* Select 8-bit input mode */
37970c0d06caSMauro Carvalho Chehab reg_w_mask(sd, OV519_R20_DFR, 0x10, 0x10);
37980c0d06caSMauro Carvalho Chehab }
37990c0d06caSMauro Carvalho Chehab break;
38000c0d06caSMauro Carvalho Chehab case SEN_OV7660:
38010c0d06caSMauro Carvalho Chehab return; /* done by ov519_set_mode/fr() */
38020c0d06caSMauro Carvalho Chehab case SEN_OV7670:
38030c0d06caSMauro Carvalho Chehab write_regvals(sd, mode_init_519_ov7670,
38040c0d06caSMauro Carvalho Chehab ARRAY_SIZE(mode_init_519_ov7670));
38050c0d06caSMauro Carvalho Chehab break;
38060c0d06caSMauro Carvalho Chehab }
38070c0d06caSMauro Carvalho Chehab
38081966bc2aSOndrej Zary reg_w(sd, OV519_R10_H_SIZE, sd->gspca_dev.pixfmt.width >> 4);
38091966bc2aSOndrej Zary reg_w(sd, OV519_R11_V_SIZE, sd->gspca_dev.pixfmt.height >> 3);
38100c0d06caSMauro Carvalho Chehab if (sd->sensor == SEN_OV7670 &&
38110c0d06caSMauro Carvalho Chehab sd->gspca_dev.cam.cam_mode[sd->gspca_dev.curr_mode].priv)
38120c0d06caSMauro Carvalho Chehab reg_w(sd, OV519_R12_X_OFFSETL, 0x04);
38130c0d06caSMauro Carvalho Chehab else if (sd->sensor == SEN_OV7648 &&
38140c0d06caSMauro Carvalho Chehab sd->gspca_dev.cam.cam_mode[sd->gspca_dev.curr_mode].priv)
38150c0d06caSMauro Carvalho Chehab reg_w(sd, OV519_R12_X_OFFSETL, 0x01);
38160c0d06caSMauro Carvalho Chehab else
38170c0d06caSMauro Carvalho Chehab reg_w(sd, OV519_R12_X_OFFSETL, 0x00);
38180c0d06caSMauro Carvalho Chehab reg_w(sd, OV519_R13_X_OFFSETH, 0x00);
38190c0d06caSMauro Carvalho Chehab reg_w(sd, OV519_R14_Y_OFFSETL, 0x00);
38200c0d06caSMauro Carvalho Chehab reg_w(sd, OV519_R15_Y_OFFSETH, 0x00);
38210c0d06caSMauro Carvalho Chehab reg_w(sd, OV519_R16_DIVIDER, 0x00);
38220c0d06caSMauro Carvalho Chehab reg_w(sd, OV519_R25_FORMAT, 0x03); /* YUV422 */
38230c0d06caSMauro Carvalho Chehab reg_w(sd, 0x26, 0x00); /* Undocumented */
38240c0d06caSMauro Carvalho Chehab
38250c0d06caSMauro Carvalho Chehab /******** Set the framerate ********/
38260c0d06caSMauro Carvalho Chehab if (frame_rate > 0)
38270c0d06caSMauro Carvalho Chehab sd->frame_rate = frame_rate;
38280c0d06caSMauro Carvalho Chehab
38290c0d06caSMauro Carvalho Chehab /* FIXME: These are only valid at the max resolution. */
38300c0d06caSMauro Carvalho Chehab sd->clockdiv = 0;
38310c0d06caSMauro Carvalho Chehab switch (sd->sensor) {
38320c0d06caSMauro Carvalho Chehab case SEN_OV7640:
38330c0d06caSMauro Carvalho Chehab case SEN_OV7648:
38340c0d06caSMauro Carvalho Chehab switch (sd->frame_rate) {
38350c0d06caSMauro Carvalho Chehab default:
38360c0d06caSMauro Carvalho Chehab /* case 30: */
38370c0d06caSMauro Carvalho Chehab reg_w(sd, 0xa4, 0x0c);
38380c0d06caSMauro Carvalho Chehab reg_w(sd, 0x23, 0xff);
38390c0d06caSMauro Carvalho Chehab break;
38400c0d06caSMauro Carvalho Chehab case 25:
38410c0d06caSMauro Carvalho Chehab reg_w(sd, 0xa4, 0x0c);
38420c0d06caSMauro Carvalho Chehab reg_w(sd, 0x23, 0x1f);
38430c0d06caSMauro Carvalho Chehab break;
38440c0d06caSMauro Carvalho Chehab case 20:
38450c0d06caSMauro Carvalho Chehab reg_w(sd, 0xa4, 0x0c);
38460c0d06caSMauro Carvalho Chehab reg_w(sd, 0x23, 0x1b);
38470c0d06caSMauro Carvalho Chehab break;
38480c0d06caSMauro Carvalho Chehab case 15:
38490c0d06caSMauro Carvalho Chehab reg_w(sd, 0xa4, 0x04);
38500c0d06caSMauro Carvalho Chehab reg_w(sd, 0x23, 0xff);
38510c0d06caSMauro Carvalho Chehab sd->clockdiv = 1;
38520c0d06caSMauro Carvalho Chehab break;
38530c0d06caSMauro Carvalho Chehab case 10:
38540c0d06caSMauro Carvalho Chehab reg_w(sd, 0xa4, 0x04);
38550c0d06caSMauro Carvalho Chehab reg_w(sd, 0x23, 0x1f);
38560c0d06caSMauro Carvalho Chehab sd->clockdiv = 1;
38570c0d06caSMauro Carvalho Chehab break;
38580c0d06caSMauro Carvalho Chehab case 5:
38590c0d06caSMauro Carvalho Chehab reg_w(sd, 0xa4, 0x04);
38600c0d06caSMauro Carvalho Chehab reg_w(sd, 0x23, 0x1b);
38610c0d06caSMauro Carvalho Chehab sd->clockdiv = 1;
38620c0d06caSMauro Carvalho Chehab break;
38630c0d06caSMauro Carvalho Chehab }
38640c0d06caSMauro Carvalho Chehab break;
38650c0d06caSMauro Carvalho Chehab case SEN_OV8610:
38660c0d06caSMauro Carvalho Chehab switch (sd->frame_rate) {
38670c0d06caSMauro Carvalho Chehab default: /* 15 fps */
38680c0d06caSMauro Carvalho Chehab /* case 15: */
38690c0d06caSMauro Carvalho Chehab reg_w(sd, 0xa4, 0x06);
38700c0d06caSMauro Carvalho Chehab reg_w(sd, 0x23, 0xff);
38710c0d06caSMauro Carvalho Chehab break;
38720c0d06caSMauro Carvalho Chehab case 10:
38730c0d06caSMauro Carvalho Chehab reg_w(sd, 0xa4, 0x06);
38740c0d06caSMauro Carvalho Chehab reg_w(sd, 0x23, 0x1f);
38750c0d06caSMauro Carvalho Chehab break;
38760c0d06caSMauro Carvalho Chehab case 5:
38770c0d06caSMauro Carvalho Chehab reg_w(sd, 0xa4, 0x06);
38780c0d06caSMauro Carvalho Chehab reg_w(sd, 0x23, 0x1b);
38790c0d06caSMauro Carvalho Chehab break;
38800c0d06caSMauro Carvalho Chehab }
38810c0d06caSMauro Carvalho Chehab break;
38820c0d06caSMauro Carvalho Chehab case SEN_OV7670: /* guesses, based on 7640 */
388337d5efb0SJoe Perches gspca_dbg(gspca_dev, D_STREAM, "Setting framerate to %d fps\n",
38840c0d06caSMauro Carvalho Chehab (sd->frame_rate == 0) ? 15 : sd->frame_rate);
38850c0d06caSMauro Carvalho Chehab reg_w(sd, 0xa4, 0x10);
38860c0d06caSMauro Carvalho Chehab switch (sd->frame_rate) {
38870c0d06caSMauro Carvalho Chehab case 30:
38880c0d06caSMauro Carvalho Chehab reg_w(sd, 0x23, 0xff);
38890c0d06caSMauro Carvalho Chehab break;
38900c0d06caSMauro Carvalho Chehab case 20:
38910c0d06caSMauro Carvalho Chehab reg_w(sd, 0x23, 0x1b);
38920c0d06caSMauro Carvalho Chehab break;
38930c0d06caSMauro Carvalho Chehab default:
38940c0d06caSMauro Carvalho Chehab /* case 15: */
38950c0d06caSMauro Carvalho Chehab reg_w(sd, 0x23, 0xff);
38960c0d06caSMauro Carvalho Chehab sd->clockdiv = 1;
38970c0d06caSMauro Carvalho Chehab break;
38980c0d06caSMauro Carvalho Chehab }
38990c0d06caSMauro Carvalho Chehab break;
39000c0d06caSMauro Carvalho Chehab }
39010c0d06caSMauro Carvalho Chehab }
39020c0d06caSMauro Carvalho Chehab
mode_init_ov_sensor_regs(struct sd * sd)39030c0d06caSMauro Carvalho Chehab static void mode_init_ov_sensor_regs(struct sd *sd)
39040c0d06caSMauro Carvalho Chehab {
3905c93396e1STheodore Kilgore struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
39060c0d06caSMauro Carvalho Chehab int qvga, xstart, xend, ystart, yend;
39070c0d06caSMauro Carvalho Chehab u8 v;
39080c0d06caSMauro Carvalho Chehab
39090c0d06caSMauro Carvalho Chehab qvga = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv & 1;
39100c0d06caSMauro Carvalho Chehab
39110c0d06caSMauro Carvalho Chehab /******** Mode (VGA/QVGA) and sensor specific regs ********/
39120c0d06caSMauro Carvalho Chehab switch (sd->sensor) {
39130c0d06caSMauro Carvalho Chehab case SEN_OV2610:
39140c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
39150c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x28, qvga ? 0x00 : 0x20, 0x20);
39160c0d06caSMauro Carvalho Chehab i2c_w(sd, 0x24, qvga ? 0x20 : 0x3a);
39170c0d06caSMauro Carvalho Chehab i2c_w(sd, 0x25, qvga ? 0x30 : 0x60);
39180c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40);
39190c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x67, qvga ? 0xf0 : 0x90, 0xf0);
39200c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20);
39210c0d06caSMauro Carvalho Chehab return;
39220c0d06caSMauro Carvalho Chehab case SEN_OV2610AE: {
39230c0d06caSMauro Carvalho Chehab u8 v;
39240c0d06caSMauro Carvalho Chehab
39250c0d06caSMauro Carvalho Chehab /* frame rates:
39260c0d06caSMauro Carvalho Chehab * 10fps / 5 fps for 1600x1200
39270c0d06caSMauro Carvalho Chehab * 40fps / 20fps for 800x600
39280c0d06caSMauro Carvalho Chehab */
39290c0d06caSMauro Carvalho Chehab v = 80;
39300c0d06caSMauro Carvalho Chehab if (qvga) {
39310c0d06caSMauro Carvalho Chehab if (sd->frame_rate < 25)
39320c0d06caSMauro Carvalho Chehab v = 0x81;
39330c0d06caSMauro Carvalho Chehab } else {
39340c0d06caSMauro Carvalho Chehab if (sd->frame_rate < 10)
39350c0d06caSMauro Carvalho Chehab v = 0x81;
39360c0d06caSMauro Carvalho Chehab }
39370c0d06caSMauro Carvalho Chehab i2c_w(sd, 0x11, v);
39380c0d06caSMauro Carvalho Chehab i2c_w(sd, 0x12, qvga ? 0x60 : 0x20);
39390c0d06caSMauro Carvalho Chehab return;
39400c0d06caSMauro Carvalho Chehab }
39410c0d06caSMauro Carvalho Chehab case SEN_OV3610:
39420c0d06caSMauro Carvalho Chehab if (qvga) {
39431966bc2aSOndrej Zary xstart = (1040 - gspca_dev->pixfmt.width) / 2 +
39441966bc2aSOndrej Zary (0x1f << 4);
39451966bc2aSOndrej Zary ystart = (776 - gspca_dev->pixfmt.height) / 2;
39460c0d06caSMauro Carvalho Chehab } else {
39471966bc2aSOndrej Zary xstart = (2076 - gspca_dev->pixfmt.width) / 2 +
39481966bc2aSOndrej Zary (0x10 << 4);
39491966bc2aSOndrej Zary ystart = (1544 - gspca_dev->pixfmt.height) / 2;
39500c0d06caSMauro Carvalho Chehab }
39511966bc2aSOndrej Zary xend = xstart + gspca_dev->pixfmt.width;
39521966bc2aSOndrej Zary yend = ystart + gspca_dev->pixfmt.height;
39530c0d06caSMauro Carvalho Chehab /* Writing to the COMH register resets the other windowing regs
39540c0d06caSMauro Carvalho Chehab to their default values, so we must do this first. */
39550c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x12, qvga ? 0x40 : 0x00, 0xf0);
39560c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x32,
39570c0d06caSMauro Carvalho Chehab (((xend >> 1) & 7) << 3) | ((xstart >> 1) & 7),
39580c0d06caSMauro Carvalho Chehab 0x3f);
39590c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x03,
39600c0d06caSMauro Carvalho Chehab (((yend >> 1) & 3) << 2) | ((ystart >> 1) & 3),
39610c0d06caSMauro Carvalho Chehab 0x0f);
39620c0d06caSMauro Carvalho Chehab i2c_w(sd, 0x17, xstart >> 4);
39630c0d06caSMauro Carvalho Chehab i2c_w(sd, 0x18, xend >> 4);
39640c0d06caSMauro Carvalho Chehab i2c_w(sd, 0x19, ystart >> 3);
39650c0d06caSMauro Carvalho Chehab i2c_w(sd, 0x1a, yend >> 3);
39660c0d06caSMauro Carvalho Chehab return;
39670c0d06caSMauro Carvalho Chehab case SEN_OV8610:
39680c0d06caSMauro Carvalho Chehab /* For OV8610 qvga means qsvga */
39690c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, OV7610_REG_COM_C, qvga ? (1 << 5) : 0, 1 << 5);
39700c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x13, 0x00, 0x20); /* Select 16 bit data bus */
39710c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */
39720c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x2d, 0x00, 0x40); /* from windrv 090403 */
39730c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x28, 0x20, 0x20); /* progressive mode on */
39740c0d06caSMauro Carvalho Chehab break;
39750c0d06caSMauro Carvalho Chehab case SEN_OV7610:
39760c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
39770c0d06caSMauro Carvalho Chehab i2c_w(sd, 0x35, qvga ? 0x1e : 0x9e);
39780c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x13, 0x00, 0x20); /* Select 16 bit data bus */
39790c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */
39800c0d06caSMauro Carvalho Chehab break;
39810c0d06caSMauro Carvalho Chehab case SEN_OV7620:
39820c0d06caSMauro Carvalho Chehab case SEN_OV7620AE:
39830c0d06caSMauro Carvalho Chehab case SEN_OV76BE:
39840c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
39850c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x28, qvga ? 0x00 : 0x20, 0x20);
39860c0d06caSMauro Carvalho Chehab i2c_w(sd, 0x24, qvga ? 0x20 : 0x3a);
39870c0d06caSMauro Carvalho Chehab i2c_w(sd, 0x25, qvga ? 0x30 : 0x60);
39880c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40);
39890c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x67, qvga ? 0xb0 : 0x90, 0xf0);
39900c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20);
39910c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x13, 0x00, 0x20); /* Select 16 bit data bus */
39920c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */
39930c0d06caSMauro Carvalho Chehab if (sd->sensor == SEN_OV76BE)
39940c0d06caSMauro Carvalho Chehab i2c_w(sd, 0x35, qvga ? 0x1e : 0x9e);
39950c0d06caSMauro Carvalho Chehab break;
39960c0d06caSMauro Carvalho Chehab case SEN_OV7640:
39970c0d06caSMauro Carvalho Chehab case SEN_OV7648:
39980c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
39990c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x28, qvga ? 0x00 : 0x20, 0x20);
40000c0d06caSMauro Carvalho Chehab /* Setting this undocumented bit in qvga mode removes a very
40010c0d06caSMauro Carvalho Chehab annoying vertical shaking of the image */
40020c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40);
40030c0d06caSMauro Carvalho Chehab /* Unknown */
40040c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x67, qvga ? 0xf0 : 0x90, 0xf0);
40050c0d06caSMauro Carvalho Chehab /* Allow higher automatic gain (to allow higher framerates) */
40060c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20);
40070c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x12, 0x04, 0x04); /* AWB: 1 */
40080c0d06caSMauro Carvalho Chehab break;
40090c0d06caSMauro Carvalho Chehab case SEN_OV7670:
40100c0d06caSMauro Carvalho Chehab /* set COM7_FMT_VGA or COM7_FMT_QVGA
40110c0d06caSMauro Carvalho Chehab * do we need to set anything else?
40120c0d06caSMauro Carvalho Chehab * HSTART etc are set in set_ov_sensor_window itself */
40130c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, OV7670_R12_COM7,
40140c0d06caSMauro Carvalho Chehab qvga ? OV7670_COM7_FMT_QVGA : OV7670_COM7_FMT_VGA,
40150c0d06caSMauro Carvalho Chehab OV7670_COM7_FMT_MASK);
40160c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x13, 0x00, 0x20); /* Select 16 bit data bus */
40170c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, OV7670_R13_COM8, OV7670_COM8_AWB,
40180c0d06caSMauro Carvalho Chehab OV7670_COM8_AWB);
40190c0d06caSMauro Carvalho Chehab if (qvga) { /* QVGA from ov7670.c by
40200c0d06caSMauro Carvalho Chehab * Jonathan Corbet */
40210c0d06caSMauro Carvalho Chehab xstart = 164;
40220c0d06caSMauro Carvalho Chehab xend = 28;
40230c0d06caSMauro Carvalho Chehab ystart = 14;
40240c0d06caSMauro Carvalho Chehab yend = 494;
40250c0d06caSMauro Carvalho Chehab } else { /* VGA */
40260c0d06caSMauro Carvalho Chehab xstart = 158;
40270c0d06caSMauro Carvalho Chehab xend = 14;
40280c0d06caSMauro Carvalho Chehab ystart = 10;
40290c0d06caSMauro Carvalho Chehab yend = 490;
40300c0d06caSMauro Carvalho Chehab }
40310c0d06caSMauro Carvalho Chehab /* OV7670 hardware window registers are split across
40320c0d06caSMauro Carvalho Chehab * multiple locations */
40330c0d06caSMauro Carvalho Chehab i2c_w(sd, OV7670_R17_HSTART, xstart >> 3);
40340c0d06caSMauro Carvalho Chehab i2c_w(sd, OV7670_R18_HSTOP, xend >> 3);
40350c0d06caSMauro Carvalho Chehab v = i2c_r(sd, OV7670_R32_HREF);
40360c0d06caSMauro Carvalho Chehab v = (v & 0xc0) | ((xend & 0x7) << 3) | (xstart & 0x07);
40370c0d06caSMauro Carvalho Chehab msleep(10); /* need to sleep between read and write to
40380c0d06caSMauro Carvalho Chehab * same reg! */
40390c0d06caSMauro Carvalho Chehab i2c_w(sd, OV7670_R32_HREF, v);
40400c0d06caSMauro Carvalho Chehab
40410c0d06caSMauro Carvalho Chehab i2c_w(sd, OV7670_R19_VSTART, ystart >> 2);
40420c0d06caSMauro Carvalho Chehab i2c_w(sd, OV7670_R1A_VSTOP, yend >> 2);
40430c0d06caSMauro Carvalho Chehab v = i2c_r(sd, OV7670_R03_VREF);
40440c0d06caSMauro Carvalho Chehab v = (v & 0xc0) | ((yend & 0x3) << 2) | (ystart & 0x03);
40450c0d06caSMauro Carvalho Chehab msleep(10); /* need to sleep between read and write to
40460c0d06caSMauro Carvalho Chehab * same reg! */
40470c0d06caSMauro Carvalho Chehab i2c_w(sd, OV7670_R03_VREF, v);
40480c0d06caSMauro Carvalho Chehab break;
40490c0d06caSMauro Carvalho Chehab case SEN_OV6620:
40500c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
40510c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x13, 0x00, 0x20); /* Select 16 bit data bus */
40520c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */
40530c0d06caSMauro Carvalho Chehab break;
40540c0d06caSMauro Carvalho Chehab case SEN_OV6630:
40550c0d06caSMauro Carvalho Chehab case SEN_OV66308AF:
40560c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
40570c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */
40580c0d06caSMauro Carvalho Chehab break;
40590c0d06caSMauro Carvalho Chehab case SEN_OV9600: {
40600c0d06caSMauro Carvalho Chehab const struct ov_i2c_regvals *vals;
40610c0d06caSMauro Carvalho Chehab static const struct ov_i2c_regvals sxga_15[] = {
40620c0d06caSMauro Carvalho Chehab {0x11, 0x80}, {0x14, 0x3e}, {0x24, 0x85}, {0x25, 0x75}
40630c0d06caSMauro Carvalho Chehab };
40640c0d06caSMauro Carvalho Chehab static const struct ov_i2c_regvals sxga_7_5[] = {
40650c0d06caSMauro Carvalho Chehab {0x11, 0x81}, {0x14, 0x3e}, {0x24, 0x85}, {0x25, 0x75}
40660c0d06caSMauro Carvalho Chehab };
40670c0d06caSMauro Carvalho Chehab static const struct ov_i2c_regvals vga_30[] = {
40680c0d06caSMauro Carvalho Chehab {0x11, 0x81}, {0x14, 0x7e}, {0x24, 0x70}, {0x25, 0x60}
40690c0d06caSMauro Carvalho Chehab };
40700c0d06caSMauro Carvalho Chehab static const struct ov_i2c_regvals vga_15[] = {
40710c0d06caSMauro Carvalho Chehab {0x11, 0x83}, {0x14, 0x3e}, {0x24, 0x80}, {0x25, 0x70}
40720c0d06caSMauro Carvalho Chehab };
40730c0d06caSMauro Carvalho Chehab
40740c0d06caSMauro Carvalho Chehab /* frame rates:
40750c0d06caSMauro Carvalho Chehab * 15fps / 7.5 fps for 1280x1024
40760c0d06caSMauro Carvalho Chehab * 30fps / 15fps for 640x480
40770c0d06caSMauro Carvalho Chehab */
40780c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x12, qvga ? 0x40 : 0x00, 0x40);
40790c0d06caSMauro Carvalho Chehab if (qvga)
40800c0d06caSMauro Carvalho Chehab vals = sd->frame_rate < 30 ? vga_15 : vga_30;
40810c0d06caSMauro Carvalho Chehab else
40820c0d06caSMauro Carvalho Chehab vals = sd->frame_rate < 15 ? sxga_7_5 : sxga_15;
40830c0d06caSMauro Carvalho Chehab write_i2c_regvals(sd, vals, ARRAY_SIZE(sxga_15));
40840c0d06caSMauro Carvalho Chehab return;
40850c0d06caSMauro Carvalho Chehab }
40860c0d06caSMauro Carvalho Chehab default:
40870c0d06caSMauro Carvalho Chehab return;
40880c0d06caSMauro Carvalho Chehab }
40890c0d06caSMauro Carvalho Chehab
40900c0d06caSMauro Carvalho Chehab /******** Clock programming ********/
40910c0d06caSMauro Carvalho Chehab i2c_w(sd, 0x11, sd->clockdiv);
40920c0d06caSMauro Carvalho Chehab }
40930c0d06caSMauro Carvalho Chehab
40940c0d06caSMauro Carvalho Chehab /* this function works for bridge ov519 and sensors ov7660 and ov7670 only */
sethvflip(struct gspca_dev * gspca_dev,s32 hflip,s32 vflip)40950c0d06caSMauro Carvalho Chehab static void sethvflip(struct gspca_dev *gspca_dev, s32 hflip, s32 vflip)
40960c0d06caSMauro Carvalho Chehab {
40970c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev;
40980c0d06caSMauro Carvalho Chehab
40990c0d06caSMauro Carvalho Chehab if (sd->gspca_dev.streaming)
41000c0d06caSMauro Carvalho Chehab reg_w(sd, OV519_R51_RESET1, 0x0f); /* block stream */
41010c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, OV7670_R1E_MVFP,
41020c0d06caSMauro Carvalho Chehab OV7670_MVFP_MIRROR * hflip | OV7670_MVFP_VFLIP * vflip,
41030c0d06caSMauro Carvalho Chehab OV7670_MVFP_MIRROR | OV7670_MVFP_VFLIP);
41040c0d06caSMauro Carvalho Chehab if (sd->gspca_dev.streaming)
41050c0d06caSMauro Carvalho Chehab reg_w(sd, OV519_R51_RESET1, 0x00); /* restart stream */
41060c0d06caSMauro Carvalho Chehab }
41070c0d06caSMauro Carvalho Chehab
set_ov_sensor_window(struct sd * sd)41080c0d06caSMauro Carvalho Chehab static void set_ov_sensor_window(struct sd *sd)
41090c0d06caSMauro Carvalho Chehab {
41100c0d06caSMauro Carvalho Chehab struct gspca_dev *gspca_dev;
41110c0d06caSMauro Carvalho Chehab int qvga, crop;
41120c0d06caSMauro Carvalho Chehab int hwsbase, hwebase, vwsbase, vwebase, hwscale, vwscale;
41130c0d06caSMauro Carvalho Chehab
41140c0d06caSMauro Carvalho Chehab /* mode setup is fully handled in mode_init_ov_sensor_regs for these */
41150c0d06caSMauro Carvalho Chehab switch (sd->sensor) {
41160c0d06caSMauro Carvalho Chehab case SEN_OV2610:
41170c0d06caSMauro Carvalho Chehab case SEN_OV2610AE:
41180c0d06caSMauro Carvalho Chehab case SEN_OV3610:
41190c0d06caSMauro Carvalho Chehab case SEN_OV7670:
41200c0d06caSMauro Carvalho Chehab case SEN_OV9600:
41210c0d06caSMauro Carvalho Chehab mode_init_ov_sensor_regs(sd);
41220c0d06caSMauro Carvalho Chehab return;
41230c0d06caSMauro Carvalho Chehab case SEN_OV7660:
41240c0d06caSMauro Carvalho Chehab ov519_set_mode(sd);
41250c0d06caSMauro Carvalho Chehab ov519_set_fr(sd);
41260c0d06caSMauro Carvalho Chehab return;
41270c0d06caSMauro Carvalho Chehab }
41280c0d06caSMauro Carvalho Chehab
41290c0d06caSMauro Carvalho Chehab gspca_dev = &sd->gspca_dev;
41300c0d06caSMauro Carvalho Chehab qvga = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv & 1;
41310c0d06caSMauro Carvalho Chehab crop = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv & 2;
41320c0d06caSMauro Carvalho Chehab
41330c0d06caSMauro Carvalho Chehab /* The different sensor ICs handle setting up of window differently.
41340c0d06caSMauro Carvalho Chehab * IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!! */
41350c0d06caSMauro Carvalho Chehab switch (sd->sensor) {
41360c0d06caSMauro Carvalho Chehab case SEN_OV8610:
41370c0d06caSMauro Carvalho Chehab hwsbase = 0x1e;
41380c0d06caSMauro Carvalho Chehab hwebase = 0x1e;
41390c0d06caSMauro Carvalho Chehab vwsbase = 0x02;
41400c0d06caSMauro Carvalho Chehab vwebase = 0x02;
41410c0d06caSMauro Carvalho Chehab break;
41420c0d06caSMauro Carvalho Chehab case SEN_OV7610:
41430c0d06caSMauro Carvalho Chehab case SEN_OV76BE:
41440c0d06caSMauro Carvalho Chehab hwsbase = 0x38;
41450c0d06caSMauro Carvalho Chehab hwebase = 0x3a;
41460c0d06caSMauro Carvalho Chehab vwsbase = vwebase = 0x05;
41470c0d06caSMauro Carvalho Chehab break;
41480c0d06caSMauro Carvalho Chehab case SEN_OV6620:
41490c0d06caSMauro Carvalho Chehab case SEN_OV6630:
41500c0d06caSMauro Carvalho Chehab case SEN_OV66308AF:
41510c0d06caSMauro Carvalho Chehab hwsbase = 0x38;
41520c0d06caSMauro Carvalho Chehab hwebase = 0x3a;
41530c0d06caSMauro Carvalho Chehab vwsbase = 0x05;
41540c0d06caSMauro Carvalho Chehab vwebase = 0x06;
41550c0d06caSMauro Carvalho Chehab if (sd->sensor == SEN_OV66308AF && qvga)
41560c0d06caSMauro Carvalho Chehab /* HDG: this fixes U and V getting swapped */
41570c0d06caSMauro Carvalho Chehab hwsbase++;
41580c0d06caSMauro Carvalho Chehab if (crop) {
41590c0d06caSMauro Carvalho Chehab hwsbase += 8;
41600c0d06caSMauro Carvalho Chehab hwebase += 8;
41610c0d06caSMauro Carvalho Chehab vwsbase += 11;
41620c0d06caSMauro Carvalho Chehab vwebase += 11;
41630c0d06caSMauro Carvalho Chehab }
41640c0d06caSMauro Carvalho Chehab break;
41650c0d06caSMauro Carvalho Chehab case SEN_OV7620:
41660c0d06caSMauro Carvalho Chehab case SEN_OV7620AE:
41670c0d06caSMauro Carvalho Chehab hwsbase = 0x2f; /* From 7620.SET (spec is wrong) */
41680c0d06caSMauro Carvalho Chehab hwebase = 0x2f;
41690c0d06caSMauro Carvalho Chehab vwsbase = vwebase = 0x05;
41700c0d06caSMauro Carvalho Chehab break;
41710c0d06caSMauro Carvalho Chehab case SEN_OV7640:
41720c0d06caSMauro Carvalho Chehab case SEN_OV7648:
41730c0d06caSMauro Carvalho Chehab hwsbase = 0x1a;
41740c0d06caSMauro Carvalho Chehab hwebase = 0x1a;
41750c0d06caSMauro Carvalho Chehab vwsbase = vwebase = 0x03;
41760c0d06caSMauro Carvalho Chehab break;
41770c0d06caSMauro Carvalho Chehab default:
41780c0d06caSMauro Carvalho Chehab return;
41790c0d06caSMauro Carvalho Chehab }
41800c0d06caSMauro Carvalho Chehab
41810c0d06caSMauro Carvalho Chehab switch (sd->sensor) {
41820c0d06caSMauro Carvalho Chehab case SEN_OV6620:
41830c0d06caSMauro Carvalho Chehab case SEN_OV6630:
41840c0d06caSMauro Carvalho Chehab case SEN_OV66308AF:
41850c0d06caSMauro Carvalho Chehab if (qvga) { /* QCIF */
41860c0d06caSMauro Carvalho Chehab hwscale = 0;
41870c0d06caSMauro Carvalho Chehab vwscale = 0;
41880c0d06caSMauro Carvalho Chehab } else { /* CIF */
41890c0d06caSMauro Carvalho Chehab hwscale = 1;
41900c0d06caSMauro Carvalho Chehab vwscale = 1; /* The datasheet says 0;
41910c0d06caSMauro Carvalho Chehab * it's wrong */
41920c0d06caSMauro Carvalho Chehab }
41930c0d06caSMauro Carvalho Chehab break;
41940c0d06caSMauro Carvalho Chehab case SEN_OV8610:
41950c0d06caSMauro Carvalho Chehab if (qvga) { /* QSVGA */
41960c0d06caSMauro Carvalho Chehab hwscale = 1;
41970c0d06caSMauro Carvalho Chehab vwscale = 1;
41980c0d06caSMauro Carvalho Chehab } else { /* SVGA */
41990c0d06caSMauro Carvalho Chehab hwscale = 2;
42000c0d06caSMauro Carvalho Chehab vwscale = 2;
42010c0d06caSMauro Carvalho Chehab }
42020c0d06caSMauro Carvalho Chehab break;
42030c0d06caSMauro Carvalho Chehab default: /* SEN_OV7xx0 */
42040c0d06caSMauro Carvalho Chehab if (qvga) { /* QVGA */
42050c0d06caSMauro Carvalho Chehab hwscale = 1;
42060c0d06caSMauro Carvalho Chehab vwscale = 0;
42070c0d06caSMauro Carvalho Chehab } else { /* VGA */
42080c0d06caSMauro Carvalho Chehab hwscale = 2;
42090c0d06caSMauro Carvalho Chehab vwscale = 1;
42100c0d06caSMauro Carvalho Chehab }
42110c0d06caSMauro Carvalho Chehab }
42120c0d06caSMauro Carvalho Chehab
42130c0d06caSMauro Carvalho Chehab mode_init_ov_sensor_regs(sd);
42140c0d06caSMauro Carvalho Chehab
42150c0d06caSMauro Carvalho Chehab i2c_w(sd, 0x17, hwsbase);
42160c0d06caSMauro Carvalho Chehab i2c_w(sd, 0x18, hwebase + (sd->sensor_width >> hwscale));
42170c0d06caSMauro Carvalho Chehab i2c_w(sd, 0x19, vwsbase);
42180c0d06caSMauro Carvalho Chehab i2c_w(sd, 0x1a, vwebase + (sd->sensor_height >> vwscale));
42190c0d06caSMauro Carvalho Chehab }
42200c0d06caSMauro Carvalho Chehab
42210c0d06caSMauro Carvalho Chehab /* -- start the camera -- */
sd_start(struct gspca_dev * gspca_dev)42220c0d06caSMauro Carvalho Chehab static int sd_start(struct gspca_dev *gspca_dev)
42230c0d06caSMauro Carvalho Chehab {
42240c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev;
42250c0d06caSMauro Carvalho Chehab
42260c0d06caSMauro Carvalho Chehab /* Default for most bridges, allow bridge_mode_init_regs to override */
42271966bc2aSOndrej Zary sd->sensor_width = sd->gspca_dev.pixfmt.width;
42281966bc2aSOndrej Zary sd->sensor_height = sd->gspca_dev.pixfmt.height;
42290c0d06caSMauro Carvalho Chehab
42300c0d06caSMauro Carvalho Chehab switch (sd->bridge) {
42310c0d06caSMauro Carvalho Chehab case BRIDGE_OV511:
42320c0d06caSMauro Carvalho Chehab case BRIDGE_OV511PLUS:
42330c0d06caSMauro Carvalho Chehab ov511_mode_init_regs(sd);
42340c0d06caSMauro Carvalho Chehab break;
42350c0d06caSMauro Carvalho Chehab case BRIDGE_OV518:
42360c0d06caSMauro Carvalho Chehab case BRIDGE_OV518PLUS:
42370c0d06caSMauro Carvalho Chehab ov518_mode_init_regs(sd);
42380c0d06caSMauro Carvalho Chehab break;
42390c0d06caSMauro Carvalho Chehab case BRIDGE_OV519:
42400c0d06caSMauro Carvalho Chehab ov519_mode_init_regs(sd);
42410c0d06caSMauro Carvalho Chehab break;
42420c0d06caSMauro Carvalho Chehab /* case BRIDGE_OVFX2: nothing to do */
42430c0d06caSMauro Carvalho Chehab case BRIDGE_W9968CF:
42440c0d06caSMauro Carvalho Chehab w9968cf_mode_init_regs(sd);
42450c0d06caSMauro Carvalho Chehab break;
42460c0d06caSMauro Carvalho Chehab }
42470c0d06caSMauro Carvalho Chehab
42480c0d06caSMauro Carvalho Chehab set_ov_sensor_window(sd);
42490c0d06caSMauro Carvalho Chehab
42500c0d06caSMauro Carvalho Chehab /* Force clear snapshot state in case the snapshot button was
42510c0d06caSMauro Carvalho Chehab pressed while we weren't streaming */
42520c0d06caSMauro Carvalho Chehab sd->snapshot_needs_reset = 1;
42530c0d06caSMauro Carvalho Chehab sd_reset_snapshot(gspca_dev);
42540c0d06caSMauro Carvalho Chehab
42550c0d06caSMauro Carvalho Chehab sd->first_frame = 3;
42560c0d06caSMauro Carvalho Chehab
42570c0d06caSMauro Carvalho Chehab ov51x_restart(sd);
42580c0d06caSMauro Carvalho Chehab ov51x_led_control(sd, 1);
42590c0d06caSMauro Carvalho Chehab return gspca_dev->usb_err;
42600c0d06caSMauro Carvalho Chehab }
42610c0d06caSMauro Carvalho Chehab
sd_stopN(struct gspca_dev * gspca_dev)42620c0d06caSMauro Carvalho Chehab static void sd_stopN(struct gspca_dev *gspca_dev)
42630c0d06caSMauro Carvalho Chehab {
42640c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev;
42650c0d06caSMauro Carvalho Chehab
42660c0d06caSMauro Carvalho Chehab ov51x_stop(sd);
42670c0d06caSMauro Carvalho Chehab ov51x_led_control(sd, 0);
42680c0d06caSMauro Carvalho Chehab }
42690c0d06caSMauro Carvalho Chehab
sd_stop0(struct gspca_dev * gspca_dev)42700c0d06caSMauro Carvalho Chehab static void sd_stop0(struct gspca_dev *gspca_dev)
42710c0d06caSMauro Carvalho Chehab {
42720c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev;
42730c0d06caSMauro Carvalho Chehab
42740c0d06caSMauro Carvalho Chehab if (!sd->gspca_dev.present)
42750c0d06caSMauro Carvalho Chehab return;
42760c0d06caSMauro Carvalho Chehab if (sd->bridge == BRIDGE_W9968CF)
42770c0d06caSMauro Carvalho Chehab w9968cf_stop0(sd);
42780c0d06caSMauro Carvalho Chehab
4279c4ea799aSPeter Senna Tschudin #if IS_ENABLED(CONFIG_INPUT)
42800c0d06caSMauro Carvalho Chehab /* If the last button state is pressed, release it now! */
42810c0d06caSMauro Carvalho Chehab if (sd->snapshot_pressed) {
42820c0d06caSMauro Carvalho Chehab input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
42830c0d06caSMauro Carvalho Chehab input_sync(gspca_dev->input_dev);
42840c0d06caSMauro Carvalho Chehab sd->snapshot_pressed = 0;
42850c0d06caSMauro Carvalho Chehab }
42860c0d06caSMauro Carvalho Chehab #endif
42870c0d06caSMauro Carvalho Chehab if (sd->bridge == BRIDGE_OV519)
42880c0d06caSMauro Carvalho Chehab reg_w(sd, OV519_R57_SNAPSHOT, 0x23);
42890c0d06caSMauro Carvalho Chehab }
42900c0d06caSMauro Carvalho Chehab
ov51x_handle_button(struct gspca_dev * gspca_dev,u8 state)42910c0d06caSMauro Carvalho Chehab static void ov51x_handle_button(struct gspca_dev *gspca_dev, u8 state)
42920c0d06caSMauro Carvalho Chehab {
42930c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev;
42940c0d06caSMauro Carvalho Chehab
42950c0d06caSMauro Carvalho Chehab if (sd->snapshot_pressed != state) {
4296c4ea799aSPeter Senna Tschudin #if IS_ENABLED(CONFIG_INPUT)
42970c0d06caSMauro Carvalho Chehab input_report_key(gspca_dev->input_dev, KEY_CAMERA, state);
42980c0d06caSMauro Carvalho Chehab input_sync(gspca_dev->input_dev);
42990c0d06caSMauro Carvalho Chehab #endif
43000c0d06caSMauro Carvalho Chehab if (state)
43010c0d06caSMauro Carvalho Chehab sd->snapshot_needs_reset = 1;
43020c0d06caSMauro Carvalho Chehab
43030c0d06caSMauro Carvalho Chehab sd->snapshot_pressed = state;
43040c0d06caSMauro Carvalho Chehab } else {
43050c0d06caSMauro Carvalho Chehab /* On the ov511 / ov519 we need to reset the button state
43060c0d06caSMauro Carvalho Chehab multiple times, as resetting does not work as long as the
43070c0d06caSMauro Carvalho Chehab button stays pressed */
43080c0d06caSMauro Carvalho Chehab switch (sd->bridge) {
43090c0d06caSMauro Carvalho Chehab case BRIDGE_OV511:
43100c0d06caSMauro Carvalho Chehab case BRIDGE_OV511PLUS:
43110c0d06caSMauro Carvalho Chehab case BRIDGE_OV519:
43120c0d06caSMauro Carvalho Chehab if (state)
43130c0d06caSMauro Carvalho Chehab sd->snapshot_needs_reset = 1;
43140c0d06caSMauro Carvalho Chehab break;
43150c0d06caSMauro Carvalho Chehab }
43160c0d06caSMauro Carvalho Chehab }
43170c0d06caSMauro Carvalho Chehab }
43180c0d06caSMauro Carvalho Chehab
ov511_pkt_scan(struct gspca_dev * gspca_dev,u8 * in,int len)43190c0d06caSMauro Carvalho Chehab static void ov511_pkt_scan(struct gspca_dev *gspca_dev,
43200c0d06caSMauro Carvalho Chehab u8 *in, /* isoc packet */
43210c0d06caSMauro Carvalho Chehab int len) /* iso packet length */
43220c0d06caSMauro Carvalho Chehab {
43230c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev;
43240c0d06caSMauro Carvalho Chehab
43250c0d06caSMauro Carvalho Chehab /* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th
43260c0d06caSMauro Carvalho Chehab * byte non-zero. The EOF packet has image width/height in the
43270c0d06caSMauro Carvalho Chehab * 10th and 11th bytes. The 9th byte is given as follows:
43280c0d06caSMauro Carvalho Chehab *
43290c0d06caSMauro Carvalho Chehab * bit 7: EOF
43300c0d06caSMauro Carvalho Chehab * 6: compression enabled
43310c0d06caSMauro Carvalho Chehab * 5: 422/420/400 modes
43320c0d06caSMauro Carvalho Chehab * 4: 422/420/400 modes
43330c0d06caSMauro Carvalho Chehab * 3: 1
43340c0d06caSMauro Carvalho Chehab * 2: snapshot button on
43350c0d06caSMauro Carvalho Chehab * 1: snapshot frame
43360c0d06caSMauro Carvalho Chehab * 0: even/odd field
43370c0d06caSMauro Carvalho Chehab */
43380c0d06caSMauro Carvalho Chehab if (!(in[0] | in[1] | in[2] | in[3] | in[4] | in[5] | in[6] | in[7]) &&
43390c0d06caSMauro Carvalho Chehab (in[8] & 0x08)) {
43400c0d06caSMauro Carvalho Chehab ov51x_handle_button(gspca_dev, (in[8] >> 2) & 1);
43410c0d06caSMauro Carvalho Chehab if (in[8] & 0x80) {
43420c0d06caSMauro Carvalho Chehab /* Frame end */
43431966bc2aSOndrej Zary if ((in[9] + 1) * 8 != gspca_dev->pixfmt.width ||
43441966bc2aSOndrej Zary (in[10] + 1) * 8 != gspca_dev->pixfmt.height) {
434552173c5fSJoe Perches gspca_err(gspca_dev, "Invalid frame size, got: %dx%d, requested: %dx%d\n",
43460c0d06caSMauro Carvalho Chehab (in[9] + 1) * 8, (in[10] + 1) * 8,
43471966bc2aSOndrej Zary gspca_dev->pixfmt.width,
43481966bc2aSOndrej Zary gspca_dev->pixfmt.height);
43490c0d06caSMauro Carvalho Chehab gspca_dev->last_packet_type = DISCARD_PACKET;
43500c0d06caSMauro Carvalho Chehab return;
43510c0d06caSMauro Carvalho Chehab }
43520c0d06caSMauro Carvalho Chehab /* Add 11 byte footer to frame, might be useful */
43530c0d06caSMauro Carvalho Chehab gspca_frame_add(gspca_dev, LAST_PACKET, in, 11);
43540c0d06caSMauro Carvalho Chehab return;
43550c0d06caSMauro Carvalho Chehab } else {
43560c0d06caSMauro Carvalho Chehab /* Frame start */
43570c0d06caSMauro Carvalho Chehab gspca_frame_add(gspca_dev, FIRST_PACKET, in, 0);
43580c0d06caSMauro Carvalho Chehab sd->packet_nr = 0;
43590c0d06caSMauro Carvalho Chehab }
43600c0d06caSMauro Carvalho Chehab }
43610c0d06caSMauro Carvalho Chehab
43620c0d06caSMauro Carvalho Chehab /* Ignore the packet number */
43630c0d06caSMauro Carvalho Chehab len--;
43640c0d06caSMauro Carvalho Chehab
43650c0d06caSMauro Carvalho Chehab /* intermediate packet */
43660c0d06caSMauro Carvalho Chehab gspca_frame_add(gspca_dev, INTER_PACKET, in, len);
43670c0d06caSMauro Carvalho Chehab }
43680c0d06caSMauro Carvalho Chehab
ov518_pkt_scan(struct gspca_dev * gspca_dev,u8 * data,int len)43690c0d06caSMauro Carvalho Chehab static void ov518_pkt_scan(struct gspca_dev *gspca_dev,
43700c0d06caSMauro Carvalho Chehab u8 *data, /* isoc packet */
43710c0d06caSMauro Carvalho Chehab int len) /* iso packet length */
43720c0d06caSMauro Carvalho Chehab {
43730c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev;
43740c0d06caSMauro Carvalho Chehab
43750c0d06caSMauro Carvalho Chehab /* A false positive here is likely, until OVT gives me
43760c0d06caSMauro Carvalho Chehab * the definitive SOF/EOF format */
43770c0d06caSMauro Carvalho Chehab if ((!(data[0] | data[1] | data[2] | data[3] | data[5])) && data[6]) {
43780c0d06caSMauro Carvalho Chehab ov51x_handle_button(gspca_dev, (data[6] >> 1) & 1);
43790c0d06caSMauro Carvalho Chehab gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
43800c0d06caSMauro Carvalho Chehab gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0);
43810c0d06caSMauro Carvalho Chehab sd->packet_nr = 0;
43820c0d06caSMauro Carvalho Chehab }
43830c0d06caSMauro Carvalho Chehab
43840c0d06caSMauro Carvalho Chehab if (gspca_dev->last_packet_type == DISCARD_PACKET)
43850c0d06caSMauro Carvalho Chehab return;
43860c0d06caSMauro Carvalho Chehab
43870c0d06caSMauro Carvalho Chehab /* Does this device use packet numbers ? */
43880c0d06caSMauro Carvalho Chehab if (len & 7) {
43890c0d06caSMauro Carvalho Chehab len--;
43900c0d06caSMauro Carvalho Chehab if (sd->packet_nr == data[len])
43910c0d06caSMauro Carvalho Chehab sd->packet_nr++;
43920c0d06caSMauro Carvalho Chehab /* The last few packets of the frame (which are all 0's
43930c0d06caSMauro Carvalho Chehab except that they may contain part of the footer), are
43940c0d06caSMauro Carvalho Chehab numbered 0 */
43950c0d06caSMauro Carvalho Chehab else if (sd->packet_nr == 0 || data[len]) {
439652173c5fSJoe Perches gspca_err(gspca_dev, "Invalid packet nr: %d (expect: %d)\n",
43970c0d06caSMauro Carvalho Chehab (int)data[len], (int)sd->packet_nr);
43980c0d06caSMauro Carvalho Chehab gspca_dev->last_packet_type = DISCARD_PACKET;
43990c0d06caSMauro Carvalho Chehab return;
44000c0d06caSMauro Carvalho Chehab }
44010c0d06caSMauro Carvalho Chehab }
44020c0d06caSMauro Carvalho Chehab
44030c0d06caSMauro Carvalho Chehab /* intermediate packet */
44040c0d06caSMauro Carvalho Chehab gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
44050c0d06caSMauro Carvalho Chehab }
44060c0d06caSMauro Carvalho Chehab
ov519_pkt_scan(struct gspca_dev * gspca_dev,u8 * data,int len)44070c0d06caSMauro Carvalho Chehab static void ov519_pkt_scan(struct gspca_dev *gspca_dev,
44080c0d06caSMauro Carvalho Chehab u8 *data, /* isoc packet */
44090c0d06caSMauro Carvalho Chehab int len) /* iso packet length */
44100c0d06caSMauro Carvalho Chehab {
44110c0d06caSMauro Carvalho Chehab /* Header of ov519 is 16 bytes:
44120c0d06caSMauro Carvalho Chehab * Byte Value Description
44130c0d06caSMauro Carvalho Chehab * 0 0xff magic
44140c0d06caSMauro Carvalho Chehab * 1 0xff magic
44150c0d06caSMauro Carvalho Chehab * 2 0xff magic
44160c0d06caSMauro Carvalho Chehab * 3 0xXX 0x50 = SOF, 0x51 = EOF
44170c0d06caSMauro Carvalho Chehab * 9 0xXX 0x01 initial frame without data,
44180c0d06caSMauro Carvalho Chehab * 0x00 standard frame with image
44190c0d06caSMauro Carvalho Chehab * 14 Lo in EOF: length of image data / 8
44200c0d06caSMauro Carvalho Chehab * 15 Hi
44210c0d06caSMauro Carvalho Chehab */
44220c0d06caSMauro Carvalho Chehab
44230c0d06caSMauro Carvalho Chehab if (data[0] == 0xff && data[1] == 0xff && data[2] == 0xff) {
44240c0d06caSMauro Carvalho Chehab switch (data[3]) {
44250c0d06caSMauro Carvalho Chehab case 0x50: /* start of frame */
44260c0d06caSMauro Carvalho Chehab /* Don't check the button state here, as the state
44270c0d06caSMauro Carvalho Chehab usually (always ?) changes at EOF and checking it
44280c0d06caSMauro Carvalho Chehab here leads to unnecessary snapshot state resets. */
44290c0d06caSMauro Carvalho Chehab #define HDRSZ 16
44300c0d06caSMauro Carvalho Chehab data += HDRSZ;
44310c0d06caSMauro Carvalho Chehab len -= HDRSZ;
44320c0d06caSMauro Carvalho Chehab #undef HDRSZ
44330c0d06caSMauro Carvalho Chehab if (data[0] == 0xff || data[1] == 0xd8)
44340c0d06caSMauro Carvalho Chehab gspca_frame_add(gspca_dev, FIRST_PACKET,
44350c0d06caSMauro Carvalho Chehab data, len);
44360c0d06caSMauro Carvalho Chehab else
44370c0d06caSMauro Carvalho Chehab gspca_dev->last_packet_type = DISCARD_PACKET;
44380c0d06caSMauro Carvalho Chehab return;
44390c0d06caSMauro Carvalho Chehab case 0x51: /* end of frame */
44400c0d06caSMauro Carvalho Chehab ov51x_handle_button(gspca_dev, data[11] & 1);
44410c0d06caSMauro Carvalho Chehab if (data[9] != 0)
44420c0d06caSMauro Carvalho Chehab gspca_dev->last_packet_type = DISCARD_PACKET;
44430c0d06caSMauro Carvalho Chehab gspca_frame_add(gspca_dev, LAST_PACKET,
44440c0d06caSMauro Carvalho Chehab NULL, 0);
44450c0d06caSMauro Carvalho Chehab return;
44460c0d06caSMauro Carvalho Chehab }
44470c0d06caSMauro Carvalho Chehab }
44480c0d06caSMauro Carvalho Chehab
44490c0d06caSMauro Carvalho Chehab /* intermediate packet */
44500c0d06caSMauro Carvalho Chehab gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
44510c0d06caSMauro Carvalho Chehab }
44520c0d06caSMauro Carvalho Chehab
ovfx2_pkt_scan(struct gspca_dev * gspca_dev,u8 * data,int len)44530c0d06caSMauro Carvalho Chehab static void ovfx2_pkt_scan(struct gspca_dev *gspca_dev,
44540c0d06caSMauro Carvalho Chehab u8 *data, /* isoc packet */
44550c0d06caSMauro Carvalho Chehab int len) /* iso packet length */
44560c0d06caSMauro Carvalho Chehab {
44570c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev;
44580c0d06caSMauro Carvalho Chehab
44590c0d06caSMauro Carvalho Chehab gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
44600c0d06caSMauro Carvalho Chehab
44610c0d06caSMauro Carvalho Chehab /* A short read signals EOF */
44620c0d06caSMauro Carvalho Chehab if (len < gspca_dev->cam.bulk_size) {
44630c0d06caSMauro Carvalho Chehab /* If the frame is short, and it is one of the first ones
44640c0d06caSMauro Carvalho Chehab the sensor and bridge are still syncing, so drop it. */
44650c0d06caSMauro Carvalho Chehab if (sd->first_frame) {
44660c0d06caSMauro Carvalho Chehab sd->first_frame--;
44670c0d06caSMauro Carvalho Chehab if (gspca_dev->image_len <
44681966bc2aSOndrej Zary sd->gspca_dev.pixfmt.width *
44691966bc2aSOndrej Zary sd->gspca_dev.pixfmt.height)
44700c0d06caSMauro Carvalho Chehab gspca_dev->last_packet_type = DISCARD_PACKET;
44710c0d06caSMauro Carvalho Chehab }
44720c0d06caSMauro Carvalho Chehab gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
44730c0d06caSMauro Carvalho Chehab gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0);
44740c0d06caSMauro Carvalho Chehab }
44750c0d06caSMauro Carvalho Chehab }
44760c0d06caSMauro Carvalho Chehab
sd_pkt_scan(struct gspca_dev * gspca_dev,u8 * data,int len)44770c0d06caSMauro Carvalho Chehab static void sd_pkt_scan(struct gspca_dev *gspca_dev,
44780c0d06caSMauro Carvalho Chehab u8 *data, /* isoc packet */
44790c0d06caSMauro Carvalho Chehab int len) /* iso packet length */
44800c0d06caSMauro Carvalho Chehab {
44810c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev;
44820c0d06caSMauro Carvalho Chehab
44830c0d06caSMauro Carvalho Chehab switch (sd->bridge) {
44840c0d06caSMauro Carvalho Chehab case BRIDGE_OV511:
44850c0d06caSMauro Carvalho Chehab case BRIDGE_OV511PLUS:
44860c0d06caSMauro Carvalho Chehab ov511_pkt_scan(gspca_dev, data, len);
44870c0d06caSMauro Carvalho Chehab break;
44880c0d06caSMauro Carvalho Chehab case BRIDGE_OV518:
44890c0d06caSMauro Carvalho Chehab case BRIDGE_OV518PLUS:
44900c0d06caSMauro Carvalho Chehab ov518_pkt_scan(gspca_dev, data, len);
44910c0d06caSMauro Carvalho Chehab break;
44920c0d06caSMauro Carvalho Chehab case BRIDGE_OV519:
44930c0d06caSMauro Carvalho Chehab ov519_pkt_scan(gspca_dev, data, len);
44940c0d06caSMauro Carvalho Chehab break;
44950c0d06caSMauro Carvalho Chehab case BRIDGE_OVFX2:
44960c0d06caSMauro Carvalho Chehab ovfx2_pkt_scan(gspca_dev, data, len);
44970c0d06caSMauro Carvalho Chehab break;
44980c0d06caSMauro Carvalho Chehab case BRIDGE_W9968CF:
44990c0d06caSMauro Carvalho Chehab w9968cf_pkt_scan(gspca_dev, data, len);
45000c0d06caSMauro Carvalho Chehab break;
45010c0d06caSMauro Carvalho Chehab }
45020c0d06caSMauro Carvalho Chehab }
45030c0d06caSMauro Carvalho Chehab
45040c0d06caSMauro Carvalho Chehab /* -- management routines -- */
45050c0d06caSMauro Carvalho Chehab
setbrightness(struct gspca_dev * gspca_dev,s32 val)45060c0d06caSMauro Carvalho Chehab static void setbrightness(struct gspca_dev *gspca_dev, s32 val)
45070c0d06caSMauro Carvalho Chehab {
45080c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev;
45090c0d06caSMauro Carvalho Chehab static const struct ov_i2c_regvals brit_7660[][7] = {
45100c0d06caSMauro Carvalho Chehab {{0x0f, 0x6a}, {0x24, 0x40}, {0x25, 0x2b}, {0x26, 0x90},
45110c0d06caSMauro Carvalho Chehab {0x27, 0xe0}, {0x28, 0xe0}, {0x2c, 0xe0}},
45120c0d06caSMauro Carvalho Chehab {{0x0f, 0x6a}, {0x24, 0x50}, {0x25, 0x40}, {0x26, 0xa1},
45130c0d06caSMauro Carvalho Chehab {0x27, 0xc0}, {0x28, 0xc0}, {0x2c, 0xc0}},
45140c0d06caSMauro Carvalho Chehab {{0x0f, 0x6a}, {0x24, 0x68}, {0x25, 0x58}, {0x26, 0xc2},
45150c0d06caSMauro Carvalho Chehab {0x27, 0xa0}, {0x28, 0xa0}, {0x2c, 0xa0}},
45160c0d06caSMauro Carvalho Chehab {{0x0f, 0x6a}, {0x24, 0x70}, {0x25, 0x68}, {0x26, 0xd3},
45170c0d06caSMauro Carvalho Chehab {0x27, 0x80}, {0x28, 0x80}, {0x2c, 0x80}},
45180c0d06caSMauro Carvalho Chehab {{0x0f, 0x6a}, {0x24, 0x80}, {0x25, 0x70}, {0x26, 0xd3},
45190c0d06caSMauro Carvalho Chehab {0x27, 0x20}, {0x28, 0x20}, {0x2c, 0x20}},
45200c0d06caSMauro Carvalho Chehab {{0x0f, 0x6a}, {0x24, 0x88}, {0x25, 0x78}, {0x26, 0xd3},
45210c0d06caSMauro Carvalho Chehab {0x27, 0x40}, {0x28, 0x40}, {0x2c, 0x40}},
45220c0d06caSMauro Carvalho Chehab {{0x0f, 0x6a}, {0x24, 0x90}, {0x25, 0x80}, {0x26, 0xd4},
45230c0d06caSMauro Carvalho Chehab {0x27, 0x60}, {0x28, 0x60}, {0x2c, 0x60}}
45240c0d06caSMauro Carvalho Chehab };
45250c0d06caSMauro Carvalho Chehab
45260c0d06caSMauro Carvalho Chehab switch (sd->sensor) {
45270c0d06caSMauro Carvalho Chehab case SEN_OV8610:
45280c0d06caSMauro Carvalho Chehab case SEN_OV7610:
45290c0d06caSMauro Carvalho Chehab case SEN_OV76BE:
45300c0d06caSMauro Carvalho Chehab case SEN_OV6620:
45310c0d06caSMauro Carvalho Chehab case SEN_OV6630:
45320c0d06caSMauro Carvalho Chehab case SEN_OV66308AF:
45330c0d06caSMauro Carvalho Chehab case SEN_OV7640:
45340c0d06caSMauro Carvalho Chehab case SEN_OV7648:
45350c0d06caSMauro Carvalho Chehab i2c_w(sd, OV7610_REG_BRT, val);
45360c0d06caSMauro Carvalho Chehab break;
45370c0d06caSMauro Carvalho Chehab case SEN_OV7620:
45380c0d06caSMauro Carvalho Chehab case SEN_OV7620AE:
45390c0d06caSMauro Carvalho Chehab i2c_w(sd, OV7610_REG_BRT, val);
45400c0d06caSMauro Carvalho Chehab break;
45410c0d06caSMauro Carvalho Chehab case SEN_OV7660:
45420c0d06caSMauro Carvalho Chehab write_i2c_regvals(sd, brit_7660[val],
45430c0d06caSMauro Carvalho Chehab ARRAY_SIZE(brit_7660[0]));
45440c0d06caSMauro Carvalho Chehab break;
45450c0d06caSMauro Carvalho Chehab case SEN_OV7670:
45460c0d06caSMauro Carvalho Chehab /*win trace
45470c0d06caSMauro Carvalho Chehab * i2c_w_mask(sd, OV7670_R13_COM8, 0, OV7670_COM8_AEC); */
45480c0d06caSMauro Carvalho Chehab i2c_w(sd, OV7670_R55_BRIGHT, ov7670_abs_to_sm(val));
45490c0d06caSMauro Carvalho Chehab break;
45500c0d06caSMauro Carvalho Chehab }
45510c0d06caSMauro Carvalho Chehab }
45520c0d06caSMauro Carvalho Chehab
setcontrast(struct gspca_dev * gspca_dev,s32 val)45530c0d06caSMauro Carvalho Chehab static void setcontrast(struct gspca_dev *gspca_dev, s32 val)
45540c0d06caSMauro Carvalho Chehab {
45550c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev;
45560c0d06caSMauro Carvalho Chehab static const struct ov_i2c_regvals contrast_7660[][31] = {
45570c0d06caSMauro Carvalho Chehab {{0x6c, 0xf0}, {0x6d, 0xf0}, {0x6e, 0xf8}, {0x6f, 0xa0},
45580c0d06caSMauro Carvalho Chehab {0x70, 0x58}, {0x71, 0x38}, {0x72, 0x30}, {0x73, 0x30},
45590c0d06caSMauro Carvalho Chehab {0x74, 0x28}, {0x75, 0x28}, {0x76, 0x24}, {0x77, 0x24},
45600c0d06caSMauro Carvalho Chehab {0x78, 0x22}, {0x79, 0x28}, {0x7a, 0x2a}, {0x7b, 0x34},
45610c0d06caSMauro Carvalho Chehab {0x7c, 0x0f}, {0x7d, 0x1e}, {0x7e, 0x3d}, {0x7f, 0x65},
45620c0d06caSMauro Carvalho Chehab {0x80, 0x70}, {0x81, 0x77}, {0x82, 0x7d}, {0x83, 0x83},
45630c0d06caSMauro Carvalho Chehab {0x84, 0x88}, {0x85, 0x8d}, {0x86, 0x96}, {0x87, 0x9f},
45640c0d06caSMauro Carvalho Chehab {0x88, 0xb0}, {0x89, 0xc4}, {0x8a, 0xd9}},
45650c0d06caSMauro Carvalho Chehab {{0x6c, 0xf0}, {0x6d, 0xf0}, {0x6e, 0xf8}, {0x6f, 0x94},
45660c0d06caSMauro Carvalho Chehab {0x70, 0x58}, {0x71, 0x40}, {0x72, 0x30}, {0x73, 0x30},
45670c0d06caSMauro Carvalho Chehab {0x74, 0x30}, {0x75, 0x30}, {0x76, 0x2c}, {0x77, 0x24},
45680c0d06caSMauro Carvalho Chehab {0x78, 0x22}, {0x79, 0x28}, {0x7a, 0x2a}, {0x7b, 0x31},
45690c0d06caSMauro Carvalho Chehab {0x7c, 0x0f}, {0x7d, 0x1e}, {0x7e, 0x3d}, {0x7f, 0x62},
45700c0d06caSMauro Carvalho Chehab {0x80, 0x6d}, {0x81, 0x75}, {0x82, 0x7b}, {0x83, 0x81},
45710c0d06caSMauro Carvalho Chehab {0x84, 0x87}, {0x85, 0x8d}, {0x86, 0x98}, {0x87, 0xa1},
45720c0d06caSMauro Carvalho Chehab {0x88, 0xb2}, {0x89, 0xc6}, {0x8a, 0xdb}},
45730c0d06caSMauro Carvalho Chehab {{0x6c, 0xf0}, {0x6d, 0xf0}, {0x6e, 0xf0}, {0x6f, 0x84},
45740c0d06caSMauro Carvalho Chehab {0x70, 0x58}, {0x71, 0x48}, {0x72, 0x40}, {0x73, 0x40},
45750c0d06caSMauro Carvalho Chehab {0x74, 0x28}, {0x75, 0x28}, {0x76, 0x28}, {0x77, 0x24},
45760c0d06caSMauro Carvalho Chehab {0x78, 0x26}, {0x79, 0x28}, {0x7a, 0x28}, {0x7b, 0x34},
45770c0d06caSMauro Carvalho Chehab {0x7c, 0x0f}, {0x7d, 0x1e}, {0x7e, 0x3c}, {0x7f, 0x5d},
45780c0d06caSMauro Carvalho Chehab {0x80, 0x68}, {0x81, 0x71}, {0x82, 0x79}, {0x83, 0x81},
45790c0d06caSMauro Carvalho Chehab {0x84, 0x86}, {0x85, 0x8b}, {0x86, 0x95}, {0x87, 0x9e},
45800c0d06caSMauro Carvalho Chehab {0x88, 0xb1}, {0x89, 0xc5}, {0x8a, 0xd9}},
45810c0d06caSMauro Carvalho Chehab {{0x6c, 0xf0}, {0x6d, 0xf0}, {0x6e, 0xf0}, {0x6f, 0x70},
45820c0d06caSMauro Carvalho Chehab {0x70, 0x58}, {0x71, 0x58}, {0x72, 0x48}, {0x73, 0x48},
45830c0d06caSMauro Carvalho Chehab {0x74, 0x38}, {0x75, 0x40}, {0x76, 0x34}, {0x77, 0x34},
45840c0d06caSMauro Carvalho Chehab {0x78, 0x2e}, {0x79, 0x28}, {0x7a, 0x24}, {0x7b, 0x22},
45850c0d06caSMauro Carvalho Chehab {0x7c, 0x0f}, {0x7d, 0x1e}, {0x7e, 0x3c}, {0x7f, 0x58},
45860c0d06caSMauro Carvalho Chehab {0x80, 0x63}, {0x81, 0x6e}, {0x82, 0x77}, {0x83, 0x80},
45870c0d06caSMauro Carvalho Chehab {0x84, 0x87}, {0x85, 0x8f}, {0x86, 0x9c}, {0x87, 0xa9},
45880c0d06caSMauro Carvalho Chehab {0x88, 0xc0}, {0x89, 0xd4}, {0x8a, 0xe6}},
45890c0d06caSMauro Carvalho Chehab {{0x6c, 0xa0}, {0x6d, 0xf0}, {0x6e, 0x90}, {0x6f, 0x80},
45900c0d06caSMauro Carvalho Chehab {0x70, 0x70}, {0x71, 0x80}, {0x72, 0x60}, {0x73, 0x60},
45910c0d06caSMauro Carvalho Chehab {0x74, 0x58}, {0x75, 0x60}, {0x76, 0x4c}, {0x77, 0x38},
45920c0d06caSMauro Carvalho Chehab {0x78, 0x38}, {0x79, 0x2a}, {0x7a, 0x20}, {0x7b, 0x0e},
45930c0d06caSMauro Carvalho Chehab {0x7c, 0x0a}, {0x7d, 0x14}, {0x7e, 0x26}, {0x7f, 0x46},
45940c0d06caSMauro Carvalho Chehab {0x80, 0x54}, {0x81, 0x64}, {0x82, 0x70}, {0x83, 0x7c},
45950c0d06caSMauro Carvalho Chehab {0x84, 0x87}, {0x85, 0x93}, {0x86, 0xa6}, {0x87, 0xb4},
45960c0d06caSMauro Carvalho Chehab {0x88, 0xd0}, {0x89, 0xe5}, {0x8a, 0xf5}},
45970c0d06caSMauro Carvalho Chehab {{0x6c, 0x60}, {0x6d, 0x80}, {0x6e, 0x60}, {0x6f, 0x80},
45980c0d06caSMauro Carvalho Chehab {0x70, 0x80}, {0x71, 0x80}, {0x72, 0x88}, {0x73, 0x30},
45990c0d06caSMauro Carvalho Chehab {0x74, 0x70}, {0x75, 0x68}, {0x76, 0x64}, {0x77, 0x50},
46000c0d06caSMauro Carvalho Chehab {0x78, 0x3c}, {0x79, 0x22}, {0x7a, 0x10}, {0x7b, 0x08},
46010c0d06caSMauro Carvalho Chehab {0x7c, 0x06}, {0x7d, 0x0e}, {0x7e, 0x1a}, {0x7f, 0x3a},
46020c0d06caSMauro Carvalho Chehab {0x80, 0x4a}, {0x81, 0x5a}, {0x82, 0x6b}, {0x83, 0x7b},
46030c0d06caSMauro Carvalho Chehab {0x84, 0x89}, {0x85, 0x96}, {0x86, 0xaf}, {0x87, 0xc3},
46040c0d06caSMauro Carvalho Chehab {0x88, 0xe1}, {0x89, 0xf2}, {0x8a, 0xfa}},
46050c0d06caSMauro Carvalho Chehab {{0x6c, 0x20}, {0x6d, 0x40}, {0x6e, 0x20}, {0x6f, 0x60},
46060c0d06caSMauro Carvalho Chehab {0x70, 0x88}, {0x71, 0xc8}, {0x72, 0xc0}, {0x73, 0xb8},
46070c0d06caSMauro Carvalho Chehab {0x74, 0xa8}, {0x75, 0xb8}, {0x76, 0x80}, {0x77, 0x5c},
46080c0d06caSMauro Carvalho Chehab {0x78, 0x26}, {0x79, 0x10}, {0x7a, 0x08}, {0x7b, 0x04},
46090c0d06caSMauro Carvalho Chehab {0x7c, 0x02}, {0x7d, 0x06}, {0x7e, 0x0a}, {0x7f, 0x22},
46100c0d06caSMauro Carvalho Chehab {0x80, 0x33}, {0x81, 0x4c}, {0x82, 0x64}, {0x83, 0x7b},
46110c0d06caSMauro Carvalho Chehab {0x84, 0x90}, {0x85, 0xa7}, {0x86, 0xc7}, {0x87, 0xde},
46120c0d06caSMauro Carvalho Chehab {0x88, 0xf1}, {0x89, 0xf9}, {0x8a, 0xfd}},
46130c0d06caSMauro Carvalho Chehab };
46140c0d06caSMauro Carvalho Chehab
46150c0d06caSMauro Carvalho Chehab switch (sd->sensor) {
46160c0d06caSMauro Carvalho Chehab case SEN_OV7610:
46170c0d06caSMauro Carvalho Chehab case SEN_OV6620:
46180c0d06caSMauro Carvalho Chehab i2c_w(sd, OV7610_REG_CNT, val);
46190c0d06caSMauro Carvalho Chehab break;
46200c0d06caSMauro Carvalho Chehab case SEN_OV6630:
46210c0d06caSMauro Carvalho Chehab case SEN_OV66308AF:
46220c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, OV7610_REG_CNT, val >> 4, 0x0f);
46230c0d06caSMauro Carvalho Chehab break;
46240c0d06caSMauro Carvalho Chehab case SEN_OV8610: {
46250c0d06caSMauro Carvalho Chehab static const u8 ctab[] = {
46260c0d06caSMauro Carvalho Chehab 0x03, 0x09, 0x0b, 0x0f, 0x53, 0x6f, 0x35, 0x7f
46270c0d06caSMauro Carvalho Chehab };
46280c0d06caSMauro Carvalho Chehab
46290c0d06caSMauro Carvalho Chehab /* Use Y gamma control instead. Bit 0 enables it. */
46300c0d06caSMauro Carvalho Chehab i2c_w(sd, 0x64, ctab[val >> 5]);
46310c0d06caSMauro Carvalho Chehab break;
46320c0d06caSMauro Carvalho Chehab }
46330c0d06caSMauro Carvalho Chehab case SEN_OV7620:
46340c0d06caSMauro Carvalho Chehab case SEN_OV7620AE: {
46350c0d06caSMauro Carvalho Chehab static const u8 ctab[] = {
46360c0d06caSMauro Carvalho Chehab 0x01, 0x05, 0x09, 0x11, 0x15, 0x35, 0x37, 0x57,
46370c0d06caSMauro Carvalho Chehab 0x5b, 0xa5, 0xa7, 0xc7, 0xc9, 0xcf, 0xef, 0xff
46380c0d06caSMauro Carvalho Chehab };
46390c0d06caSMauro Carvalho Chehab
46400c0d06caSMauro Carvalho Chehab /* Use Y gamma control instead. Bit 0 enables it. */
46410c0d06caSMauro Carvalho Chehab i2c_w(sd, 0x64, ctab[val >> 4]);
46420c0d06caSMauro Carvalho Chehab break;
46430c0d06caSMauro Carvalho Chehab }
46440c0d06caSMauro Carvalho Chehab case SEN_OV7660:
46450c0d06caSMauro Carvalho Chehab write_i2c_regvals(sd, contrast_7660[val],
46460c0d06caSMauro Carvalho Chehab ARRAY_SIZE(contrast_7660[0]));
46470c0d06caSMauro Carvalho Chehab break;
46480c0d06caSMauro Carvalho Chehab case SEN_OV7670:
46490c0d06caSMauro Carvalho Chehab /* check that this isn't just the same as ov7610 */
46500c0d06caSMauro Carvalho Chehab i2c_w(sd, OV7670_R56_CONTRAS, val >> 1);
46510c0d06caSMauro Carvalho Chehab break;
46520c0d06caSMauro Carvalho Chehab }
46530c0d06caSMauro Carvalho Chehab }
46540c0d06caSMauro Carvalho Chehab
setexposure(struct gspca_dev * gspca_dev,s32 val)46550c0d06caSMauro Carvalho Chehab static void setexposure(struct gspca_dev *gspca_dev, s32 val)
46560c0d06caSMauro Carvalho Chehab {
46570c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev;
46580c0d06caSMauro Carvalho Chehab
46590c0d06caSMauro Carvalho Chehab i2c_w(sd, 0x10, val);
46600c0d06caSMauro Carvalho Chehab }
46610c0d06caSMauro Carvalho Chehab
setcolors(struct gspca_dev * gspca_dev,s32 val)46620c0d06caSMauro Carvalho Chehab static void setcolors(struct gspca_dev *gspca_dev, s32 val)
46630c0d06caSMauro Carvalho Chehab {
46640c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev;
46650c0d06caSMauro Carvalho Chehab static const struct ov_i2c_regvals colors_7660[][6] = {
46660c0d06caSMauro Carvalho Chehab {{0x4f, 0x28}, {0x50, 0x2a}, {0x51, 0x02}, {0x52, 0x0a},
46670c0d06caSMauro Carvalho Chehab {0x53, 0x19}, {0x54, 0x23}},
46680c0d06caSMauro Carvalho Chehab {{0x4f, 0x47}, {0x50, 0x4a}, {0x51, 0x03}, {0x52, 0x11},
46690c0d06caSMauro Carvalho Chehab {0x53, 0x2c}, {0x54, 0x3e}},
46700c0d06caSMauro Carvalho Chehab {{0x4f, 0x66}, {0x50, 0x6b}, {0x51, 0x05}, {0x52, 0x19},
46710c0d06caSMauro Carvalho Chehab {0x53, 0x40}, {0x54, 0x59}},
46720c0d06caSMauro Carvalho Chehab {{0x4f, 0x84}, {0x50, 0x8b}, {0x51, 0x06}, {0x52, 0x20},
46730c0d06caSMauro Carvalho Chehab {0x53, 0x53}, {0x54, 0x73}},
46740c0d06caSMauro Carvalho Chehab {{0x4f, 0xa3}, {0x50, 0xab}, {0x51, 0x08}, {0x52, 0x28},
46750c0d06caSMauro Carvalho Chehab {0x53, 0x66}, {0x54, 0x8e}},
46760c0d06caSMauro Carvalho Chehab };
46770c0d06caSMauro Carvalho Chehab
46780c0d06caSMauro Carvalho Chehab switch (sd->sensor) {
46790c0d06caSMauro Carvalho Chehab case SEN_OV8610:
46800c0d06caSMauro Carvalho Chehab case SEN_OV7610:
46810c0d06caSMauro Carvalho Chehab case SEN_OV76BE:
46820c0d06caSMauro Carvalho Chehab case SEN_OV6620:
46830c0d06caSMauro Carvalho Chehab case SEN_OV6630:
46840c0d06caSMauro Carvalho Chehab case SEN_OV66308AF:
46850c0d06caSMauro Carvalho Chehab i2c_w(sd, OV7610_REG_SAT, val);
46860c0d06caSMauro Carvalho Chehab break;
46870c0d06caSMauro Carvalho Chehab case SEN_OV7620:
46880c0d06caSMauro Carvalho Chehab case SEN_OV7620AE:
46890c0d06caSMauro Carvalho Chehab /* Use UV gamma control instead. Bits 0 & 7 are reserved. */
46900c0d06caSMauro Carvalho Chehab /* rc = ov_i2c_write(sd->dev, 0x62, (val >> 9) & 0x7e);
46910c0d06caSMauro Carvalho Chehab if (rc < 0)
46920c0d06caSMauro Carvalho Chehab goto out; */
46930c0d06caSMauro Carvalho Chehab i2c_w(sd, OV7610_REG_SAT, val);
46940c0d06caSMauro Carvalho Chehab break;
46950c0d06caSMauro Carvalho Chehab case SEN_OV7640:
46960c0d06caSMauro Carvalho Chehab case SEN_OV7648:
46970c0d06caSMauro Carvalho Chehab i2c_w(sd, OV7610_REG_SAT, val & 0xf0);
46980c0d06caSMauro Carvalho Chehab break;
46990c0d06caSMauro Carvalho Chehab case SEN_OV7660:
47000c0d06caSMauro Carvalho Chehab write_i2c_regvals(sd, colors_7660[val],
47010c0d06caSMauro Carvalho Chehab ARRAY_SIZE(colors_7660[0]));
47020c0d06caSMauro Carvalho Chehab break;
47030c0d06caSMauro Carvalho Chehab case SEN_OV7670:
47040c0d06caSMauro Carvalho Chehab /* supported later once I work out how to do it
47050c0d06caSMauro Carvalho Chehab * transparently fail now! */
47060c0d06caSMauro Carvalho Chehab /* set REG_COM13 values for UV sat auto mode */
47070c0d06caSMauro Carvalho Chehab break;
47080c0d06caSMauro Carvalho Chehab }
47090c0d06caSMauro Carvalho Chehab }
47100c0d06caSMauro Carvalho Chehab
setautobright(struct gspca_dev * gspca_dev,s32 val)47110c0d06caSMauro Carvalho Chehab static void setautobright(struct gspca_dev *gspca_dev, s32 val)
47120c0d06caSMauro Carvalho Chehab {
47130c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev;
47140c0d06caSMauro Carvalho Chehab
47150c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x2d, val ? 0x10 : 0x00, 0x10);
47160c0d06caSMauro Carvalho Chehab }
47170c0d06caSMauro Carvalho Chehab
setfreq_i(struct sd * sd,s32 val)47180c0d06caSMauro Carvalho Chehab static void setfreq_i(struct sd *sd, s32 val)
47190c0d06caSMauro Carvalho Chehab {
47200c0d06caSMauro Carvalho Chehab if (sd->sensor == SEN_OV7660
47210c0d06caSMauro Carvalho Chehab || sd->sensor == SEN_OV7670) {
47220c0d06caSMauro Carvalho Chehab switch (val) {
47230c0d06caSMauro Carvalho Chehab case 0: /* Banding filter disabled */
47240c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, OV7670_R13_COM8, 0, OV7670_COM8_BFILT);
47250c0d06caSMauro Carvalho Chehab break;
47260c0d06caSMauro Carvalho Chehab case 1: /* 50 hz */
47270c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, OV7670_R13_COM8, OV7670_COM8_BFILT,
47280c0d06caSMauro Carvalho Chehab OV7670_COM8_BFILT);
47290c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, OV7670_R3B_COM11, 0x08, 0x18);
47300c0d06caSMauro Carvalho Chehab break;
47310c0d06caSMauro Carvalho Chehab case 2: /* 60 hz */
47320c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, OV7670_R13_COM8, OV7670_COM8_BFILT,
47330c0d06caSMauro Carvalho Chehab OV7670_COM8_BFILT);
47340c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, OV7670_R3B_COM11, 0x00, 0x18);
47350c0d06caSMauro Carvalho Chehab break;
47360c0d06caSMauro Carvalho Chehab case 3: /* Auto hz - ov7670 only */
47370c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, OV7670_R13_COM8, OV7670_COM8_BFILT,
47380c0d06caSMauro Carvalho Chehab OV7670_COM8_BFILT);
47390c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, OV7670_R3B_COM11, OV7670_COM11_HZAUTO,
47400c0d06caSMauro Carvalho Chehab 0x18);
47410c0d06caSMauro Carvalho Chehab break;
47420c0d06caSMauro Carvalho Chehab }
47430c0d06caSMauro Carvalho Chehab } else {
47440c0d06caSMauro Carvalho Chehab switch (val) {
47450c0d06caSMauro Carvalho Chehab case 0: /* Banding filter disabled */
47460c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x2d, 0x00, 0x04);
47470c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x2a, 0x00, 0x80);
47480c0d06caSMauro Carvalho Chehab break;
47490c0d06caSMauro Carvalho Chehab case 1: /* 50 hz (filter on and framerate adj) */
47500c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x2d, 0x04, 0x04);
47510c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x2a, 0x80, 0x80);
47520c0d06caSMauro Carvalho Chehab /* 20 fps -> 16.667 fps */
47530c0d06caSMauro Carvalho Chehab if (sd->sensor == SEN_OV6620 ||
47540c0d06caSMauro Carvalho Chehab sd->sensor == SEN_OV6630 ||
47550c0d06caSMauro Carvalho Chehab sd->sensor == SEN_OV66308AF)
47560c0d06caSMauro Carvalho Chehab i2c_w(sd, 0x2b, 0x5e);
47570c0d06caSMauro Carvalho Chehab else
47580c0d06caSMauro Carvalho Chehab i2c_w(sd, 0x2b, 0xac);
47590c0d06caSMauro Carvalho Chehab break;
47600c0d06caSMauro Carvalho Chehab case 2: /* 60 hz (filter on, ...) */
47610c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x2d, 0x04, 0x04);
47620c0d06caSMauro Carvalho Chehab if (sd->sensor == SEN_OV6620 ||
47630c0d06caSMauro Carvalho Chehab sd->sensor == SEN_OV6630 ||
47640c0d06caSMauro Carvalho Chehab sd->sensor == SEN_OV66308AF) {
47650c0d06caSMauro Carvalho Chehab /* 20 fps -> 15 fps */
47660c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x2a, 0x80, 0x80);
47670c0d06caSMauro Carvalho Chehab i2c_w(sd, 0x2b, 0xa8);
47680c0d06caSMauro Carvalho Chehab } else {
47690c0d06caSMauro Carvalho Chehab /* no framerate adj. */
47700c0d06caSMauro Carvalho Chehab i2c_w_mask(sd, 0x2a, 0x00, 0x80);
47710c0d06caSMauro Carvalho Chehab }
47720c0d06caSMauro Carvalho Chehab break;
47730c0d06caSMauro Carvalho Chehab }
47740c0d06caSMauro Carvalho Chehab }
47750c0d06caSMauro Carvalho Chehab }
47760c0d06caSMauro Carvalho Chehab
setfreq(struct gspca_dev * gspca_dev,s32 val)47770c0d06caSMauro Carvalho Chehab static void setfreq(struct gspca_dev *gspca_dev, s32 val)
47780c0d06caSMauro Carvalho Chehab {
47790c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev;
47800c0d06caSMauro Carvalho Chehab
47810c0d06caSMauro Carvalho Chehab setfreq_i(sd, val);
47820c0d06caSMauro Carvalho Chehab
47830c0d06caSMauro Carvalho Chehab /* Ugly but necessary */
47840c0d06caSMauro Carvalho Chehab if (sd->bridge == BRIDGE_W9968CF)
47850c0d06caSMauro Carvalho Chehab w9968cf_set_crop_window(sd);
47860c0d06caSMauro Carvalho Chehab }
47870c0d06caSMauro Carvalho Chehab
sd_get_jcomp(struct gspca_dev * gspca_dev,struct v4l2_jpegcompression * jcomp)47880c0d06caSMauro Carvalho Chehab static int sd_get_jcomp(struct gspca_dev *gspca_dev,
47890c0d06caSMauro Carvalho Chehab struct v4l2_jpegcompression *jcomp)
47900c0d06caSMauro Carvalho Chehab {
47910c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev;
47920c0d06caSMauro Carvalho Chehab
47930c0d06caSMauro Carvalho Chehab if (sd->bridge != BRIDGE_W9968CF)
47940c0d06caSMauro Carvalho Chehab return -ENOTTY;
47950c0d06caSMauro Carvalho Chehab
47960c0d06caSMauro Carvalho Chehab memset(jcomp, 0, sizeof *jcomp);
47970c0d06caSMauro Carvalho Chehab jcomp->quality = v4l2_ctrl_g_ctrl(sd->jpegqual);
47980c0d06caSMauro Carvalho Chehab jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT | V4L2_JPEG_MARKER_DQT |
47990c0d06caSMauro Carvalho Chehab V4L2_JPEG_MARKER_DRI;
48000c0d06caSMauro Carvalho Chehab return 0;
48010c0d06caSMauro Carvalho Chehab }
48020c0d06caSMauro Carvalho Chehab
sd_set_jcomp(struct gspca_dev * gspca_dev,const struct v4l2_jpegcompression * jcomp)48030c0d06caSMauro Carvalho Chehab static int sd_set_jcomp(struct gspca_dev *gspca_dev,
4804d88aab53SHans Verkuil const struct v4l2_jpegcompression *jcomp)
48050c0d06caSMauro Carvalho Chehab {
48060c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev;
48070c0d06caSMauro Carvalho Chehab
48080c0d06caSMauro Carvalho Chehab if (sd->bridge != BRIDGE_W9968CF)
48090c0d06caSMauro Carvalho Chehab return -ENOTTY;
48100c0d06caSMauro Carvalho Chehab
48110c0d06caSMauro Carvalho Chehab v4l2_ctrl_s_ctrl(sd->jpegqual, jcomp->quality);
48120c0d06caSMauro Carvalho Chehab return 0;
48130c0d06caSMauro Carvalho Chehab }
48140c0d06caSMauro Carvalho Chehab
sd_g_volatile_ctrl(struct v4l2_ctrl * ctrl)48150c0d06caSMauro Carvalho Chehab static int sd_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
48160c0d06caSMauro Carvalho Chehab {
48170c0d06caSMauro Carvalho Chehab struct gspca_dev *gspca_dev =
48180c0d06caSMauro Carvalho Chehab container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
48190c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *)gspca_dev;
48200c0d06caSMauro Carvalho Chehab
48210c0d06caSMauro Carvalho Chehab gspca_dev->usb_err = 0;
48220c0d06caSMauro Carvalho Chehab
48230c0d06caSMauro Carvalho Chehab switch (ctrl->id) {
48240c0d06caSMauro Carvalho Chehab case V4L2_CID_AUTOGAIN:
48250c0d06caSMauro Carvalho Chehab gspca_dev->exposure->val = i2c_r(sd, 0x10);
48260c0d06caSMauro Carvalho Chehab break;
48270c0d06caSMauro Carvalho Chehab }
48280c0d06caSMauro Carvalho Chehab return 0;
48290c0d06caSMauro Carvalho Chehab }
48300c0d06caSMauro Carvalho Chehab
sd_s_ctrl(struct v4l2_ctrl * ctrl)48310c0d06caSMauro Carvalho Chehab static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
48320c0d06caSMauro Carvalho Chehab {
48330c0d06caSMauro Carvalho Chehab struct gspca_dev *gspca_dev =
48340c0d06caSMauro Carvalho Chehab container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
48350c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *)gspca_dev;
48360c0d06caSMauro Carvalho Chehab
48370c0d06caSMauro Carvalho Chehab gspca_dev->usb_err = 0;
48380c0d06caSMauro Carvalho Chehab
48390c0d06caSMauro Carvalho Chehab if (!gspca_dev->streaming)
48400c0d06caSMauro Carvalho Chehab return 0;
48410c0d06caSMauro Carvalho Chehab
48420c0d06caSMauro Carvalho Chehab switch (ctrl->id) {
48430c0d06caSMauro Carvalho Chehab case V4L2_CID_BRIGHTNESS:
48440c0d06caSMauro Carvalho Chehab setbrightness(gspca_dev, ctrl->val);
48450c0d06caSMauro Carvalho Chehab break;
48460c0d06caSMauro Carvalho Chehab case V4L2_CID_CONTRAST:
48470c0d06caSMauro Carvalho Chehab setcontrast(gspca_dev, ctrl->val);
48480c0d06caSMauro Carvalho Chehab break;
48490c0d06caSMauro Carvalho Chehab case V4L2_CID_POWER_LINE_FREQUENCY:
48500c0d06caSMauro Carvalho Chehab setfreq(gspca_dev, ctrl->val);
48510c0d06caSMauro Carvalho Chehab break;
48520c0d06caSMauro Carvalho Chehab case V4L2_CID_AUTOBRIGHTNESS:
48530c0d06caSMauro Carvalho Chehab if (ctrl->is_new)
48540c0d06caSMauro Carvalho Chehab setautobright(gspca_dev, ctrl->val);
48550c0d06caSMauro Carvalho Chehab if (!ctrl->val && sd->brightness->is_new)
48560c0d06caSMauro Carvalho Chehab setbrightness(gspca_dev, sd->brightness->val);
48570c0d06caSMauro Carvalho Chehab break;
48580c0d06caSMauro Carvalho Chehab case V4L2_CID_SATURATION:
48590c0d06caSMauro Carvalho Chehab setcolors(gspca_dev, ctrl->val);
48600c0d06caSMauro Carvalho Chehab break;
48610c0d06caSMauro Carvalho Chehab case V4L2_CID_HFLIP:
48620c0d06caSMauro Carvalho Chehab sethvflip(gspca_dev, ctrl->val, sd->vflip->val);
48630c0d06caSMauro Carvalho Chehab break;
48640c0d06caSMauro Carvalho Chehab case V4L2_CID_AUTOGAIN:
48650c0d06caSMauro Carvalho Chehab if (ctrl->is_new)
48660c0d06caSMauro Carvalho Chehab setautogain(gspca_dev, ctrl->val);
48670c0d06caSMauro Carvalho Chehab if (!ctrl->val && gspca_dev->exposure->is_new)
48680c0d06caSMauro Carvalho Chehab setexposure(gspca_dev, gspca_dev->exposure->val);
48690c0d06caSMauro Carvalho Chehab break;
48700c0d06caSMauro Carvalho Chehab case V4L2_CID_JPEG_COMPRESSION_QUALITY:
48710c0d06caSMauro Carvalho Chehab return -EBUSY; /* Should never happen, as we grab the ctrl */
48720c0d06caSMauro Carvalho Chehab }
48730c0d06caSMauro Carvalho Chehab return gspca_dev->usb_err;
48740c0d06caSMauro Carvalho Chehab }
48750c0d06caSMauro Carvalho Chehab
48760c0d06caSMauro Carvalho Chehab static const struct v4l2_ctrl_ops sd_ctrl_ops = {
48770c0d06caSMauro Carvalho Chehab .g_volatile_ctrl = sd_g_volatile_ctrl,
48780c0d06caSMauro Carvalho Chehab .s_ctrl = sd_s_ctrl,
48790c0d06caSMauro Carvalho Chehab };
48800c0d06caSMauro Carvalho Chehab
sd_init_controls(struct gspca_dev * gspca_dev)48810c0d06caSMauro Carvalho Chehab static int sd_init_controls(struct gspca_dev *gspca_dev)
48820c0d06caSMauro Carvalho Chehab {
48830c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *)gspca_dev;
48840c0d06caSMauro Carvalho Chehab struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
48850c0d06caSMauro Carvalho Chehab
48860c0d06caSMauro Carvalho Chehab gspca_dev->vdev.ctrl_handler = hdl;
48870c0d06caSMauro Carvalho Chehab v4l2_ctrl_handler_init(hdl, 10);
48880c0d06caSMauro Carvalho Chehab if (valid_controls[sd->sensor].has_brightness)
48890c0d06caSMauro Carvalho Chehab sd->brightness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
48900c0d06caSMauro Carvalho Chehab V4L2_CID_BRIGHTNESS, 0,
48910c0d06caSMauro Carvalho Chehab sd->sensor == SEN_OV7660 ? 6 : 255, 1,
48920c0d06caSMauro Carvalho Chehab sd->sensor == SEN_OV7660 ? 3 : 127);
48930c0d06caSMauro Carvalho Chehab if (valid_controls[sd->sensor].has_contrast) {
48940c0d06caSMauro Carvalho Chehab if (sd->sensor == SEN_OV7660)
48950c0d06caSMauro Carvalho Chehab v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
48960c0d06caSMauro Carvalho Chehab V4L2_CID_CONTRAST, 0, 6, 1, 3);
48970c0d06caSMauro Carvalho Chehab else
48980c0d06caSMauro Carvalho Chehab v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
48990c0d06caSMauro Carvalho Chehab V4L2_CID_CONTRAST, 0, 255, 1,
49000c0d06caSMauro Carvalho Chehab (sd->sensor == SEN_OV6630 ||
49010c0d06caSMauro Carvalho Chehab sd->sensor == SEN_OV66308AF) ? 200 : 127);
49020c0d06caSMauro Carvalho Chehab }
49030c0d06caSMauro Carvalho Chehab if (valid_controls[sd->sensor].has_sat)
49040c0d06caSMauro Carvalho Chehab v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
49050c0d06caSMauro Carvalho Chehab V4L2_CID_SATURATION, 0,
49060c0d06caSMauro Carvalho Chehab sd->sensor == SEN_OV7660 ? 4 : 255, 1,
49070c0d06caSMauro Carvalho Chehab sd->sensor == SEN_OV7660 ? 2 : 127);
49080c0d06caSMauro Carvalho Chehab if (valid_controls[sd->sensor].has_exposure)
49090c0d06caSMauro Carvalho Chehab gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
49100c0d06caSMauro Carvalho Chehab V4L2_CID_EXPOSURE, 0, 255, 1, 127);
49110c0d06caSMauro Carvalho Chehab if (valid_controls[sd->sensor].has_hvflip) {
49120c0d06caSMauro Carvalho Chehab sd->hflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
49130c0d06caSMauro Carvalho Chehab V4L2_CID_HFLIP, 0, 1, 1, 0);
49140c0d06caSMauro Carvalho Chehab sd->vflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
49150c0d06caSMauro Carvalho Chehab V4L2_CID_VFLIP, 0, 1, 1, 0);
49160c0d06caSMauro Carvalho Chehab }
49170c0d06caSMauro Carvalho Chehab if (valid_controls[sd->sensor].has_autobright)
49180c0d06caSMauro Carvalho Chehab sd->autobright = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
49190c0d06caSMauro Carvalho Chehab V4L2_CID_AUTOBRIGHTNESS, 0, 1, 1, 1);
49200c0d06caSMauro Carvalho Chehab if (valid_controls[sd->sensor].has_autogain)
49210c0d06caSMauro Carvalho Chehab gspca_dev->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
49220c0d06caSMauro Carvalho Chehab V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
49230c0d06caSMauro Carvalho Chehab if (valid_controls[sd->sensor].has_freq) {
49240c0d06caSMauro Carvalho Chehab if (sd->sensor == SEN_OV7670)
49250c0d06caSMauro Carvalho Chehab sd->freq = v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops,
49260c0d06caSMauro Carvalho Chehab V4L2_CID_POWER_LINE_FREQUENCY,
49270c0d06caSMauro Carvalho Chehab V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0,
49280c0d06caSMauro Carvalho Chehab V4L2_CID_POWER_LINE_FREQUENCY_AUTO);
49290c0d06caSMauro Carvalho Chehab else
49300c0d06caSMauro Carvalho Chehab sd->freq = v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops,
49310c0d06caSMauro Carvalho Chehab V4L2_CID_POWER_LINE_FREQUENCY,
49320c0d06caSMauro Carvalho Chehab V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0, 0);
49330c0d06caSMauro Carvalho Chehab }
49340c0d06caSMauro Carvalho Chehab if (sd->bridge == BRIDGE_W9968CF)
49350c0d06caSMauro Carvalho Chehab sd->jpegqual = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
49360c0d06caSMauro Carvalho Chehab V4L2_CID_JPEG_COMPRESSION_QUALITY,
49370c0d06caSMauro Carvalho Chehab QUALITY_MIN, QUALITY_MAX, 1, QUALITY_DEF);
49380c0d06caSMauro Carvalho Chehab
49390c0d06caSMauro Carvalho Chehab if (hdl->error) {
494052173c5fSJoe Perches gspca_err(gspca_dev, "Could not initialize controls\n");
49410c0d06caSMauro Carvalho Chehab return hdl->error;
49420c0d06caSMauro Carvalho Chehab }
49430c0d06caSMauro Carvalho Chehab if (gspca_dev->autogain)
49440c0d06caSMauro Carvalho Chehab v4l2_ctrl_auto_cluster(3, &gspca_dev->autogain, 0, true);
49450c0d06caSMauro Carvalho Chehab if (sd->autobright)
49460c0d06caSMauro Carvalho Chehab v4l2_ctrl_auto_cluster(2, &sd->autobright, 0, false);
49470c0d06caSMauro Carvalho Chehab if (sd->hflip)
49480c0d06caSMauro Carvalho Chehab v4l2_ctrl_cluster(2, &sd->hflip);
49490c0d06caSMauro Carvalho Chehab return 0;
49500c0d06caSMauro Carvalho Chehab }
49510c0d06caSMauro Carvalho Chehab
49520c0d06caSMauro Carvalho Chehab /* sub-driver description */
49530c0d06caSMauro Carvalho Chehab static const struct sd_desc sd_desc = {
49540c0d06caSMauro Carvalho Chehab .name = MODULE_NAME,
49550c0d06caSMauro Carvalho Chehab .config = sd_config,
49560c0d06caSMauro Carvalho Chehab .init = sd_init,
49570c0d06caSMauro Carvalho Chehab .init_controls = sd_init_controls,
49580c0d06caSMauro Carvalho Chehab .isoc_init = sd_isoc_init,
49590c0d06caSMauro Carvalho Chehab .start = sd_start,
49600c0d06caSMauro Carvalho Chehab .stopN = sd_stopN,
49610c0d06caSMauro Carvalho Chehab .stop0 = sd_stop0,
49620c0d06caSMauro Carvalho Chehab .pkt_scan = sd_pkt_scan,
49630c0d06caSMauro Carvalho Chehab .dq_callback = sd_reset_snapshot,
49640c0d06caSMauro Carvalho Chehab .get_jcomp = sd_get_jcomp,
49650c0d06caSMauro Carvalho Chehab .set_jcomp = sd_set_jcomp,
4966c4ea799aSPeter Senna Tschudin #if IS_ENABLED(CONFIG_INPUT)
49670c0d06caSMauro Carvalho Chehab .other_input = 1,
49680c0d06caSMauro Carvalho Chehab #endif
49690c0d06caSMauro Carvalho Chehab };
49700c0d06caSMauro Carvalho Chehab
49710c0d06caSMauro Carvalho Chehab /* -- module initialisation -- */
49720c0d06caSMauro Carvalho Chehab static const struct usb_device_id device_table[] = {
49730c0d06caSMauro Carvalho Chehab {USB_DEVICE(0x041e, 0x4003), .driver_info = BRIDGE_W9968CF },
49740c0d06caSMauro Carvalho Chehab {USB_DEVICE(0x041e, 0x4052),
49750c0d06caSMauro Carvalho Chehab .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
49760c0d06caSMauro Carvalho Chehab {USB_DEVICE(0x041e, 0x405f), .driver_info = BRIDGE_OV519 },
49770c0d06caSMauro Carvalho Chehab {USB_DEVICE(0x041e, 0x4060), .driver_info = BRIDGE_OV519 },
49780c0d06caSMauro Carvalho Chehab {USB_DEVICE(0x041e, 0x4061), .driver_info = BRIDGE_OV519 },
49790c0d06caSMauro Carvalho Chehab {USB_DEVICE(0x041e, 0x4064), .driver_info = BRIDGE_OV519 },
49800c0d06caSMauro Carvalho Chehab {USB_DEVICE(0x041e, 0x4067), .driver_info = BRIDGE_OV519 },
49810c0d06caSMauro Carvalho Chehab {USB_DEVICE(0x041e, 0x4068), .driver_info = BRIDGE_OV519 },
49820c0d06caSMauro Carvalho Chehab {USB_DEVICE(0x045e, 0x028c),
49830c0d06caSMauro Carvalho Chehab .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
49840c0d06caSMauro Carvalho Chehab {USB_DEVICE(0x054c, 0x0154), .driver_info = BRIDGE_OV519 },
49850c0d06caSMauro Carvalho Chehab {USB_DEVICE(0x054c, 0x0155), .driver_info = BRIDGE_OV519 },
49860c0d06caSMauro Carvalho Chehab {USB_DEVICE(0x05a9, 0x0511), .driver_info = BRIDGE_OV511 },
49870c0d06caSMauro Carvalho Chehab {USB_DEVICE(0x05a9, 0x0518), .driver_info = BRIDGE_OV518 },
49880c0d06caSMauro Carvalho Chehab {USB_DEVICE(0x05a9, 0x0519),
49890c0d06caSMauro Carvalho Chehab .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
49900c0d06caSMauro Carvalho Chehab {USB_DEVICE(0x05a9, 0x0530),
49910c0d06caSMauro Carvalho Chehab .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
49920c0d06caSMauro Carvalho Chehab {USB_DEVICE(0x05a9, 0x2800), .driver_info = BRIDGE_OVFX2 },
49930c0d06caSMauro Carvalho Chehab {USB_DEVICE(0x05a9, 0x4519), .driver_info = BRIDGE_OV519 },
49940c0d06caSMauro Carvalho Chehab {USB_DEVICE(0x05a9, 0x8519), .driver_info = BRIDGE_OV519 },
49950c0d06caSMauro Carvalho Chehab {USB_DEVICE(0x05a9, 0xa511), .driver_info = BRIDGE_OV511PLUS },
49960c0d06caSMauro Carvalho Chehab {USB_DEVICE(0x05a9, 0xa518), .driver_info = BRIDGE_OV518PLUS },
49970c0d06caSMauro Carvalho Chehab {USB_DEVICE(0x0813, 0x0002), .driver_info = BRIDGE_OV511PLUS },
49980c0d06caSMauro Carvalho Chehab {USB_DEVICE(0x0b62, 0x0059), .driver_info = BRIDGE_OVFX2 },
49990c0d06caSMauro Carvalho Chehab {USB_DEVICE(0x0e96, 0xc001), .driver_info = BRIDGE_OVFX2 },
50000c0d06caSMauro Carvalho Chehab {USB_DEVICE(0x1046, 0x9967), .driver_info = BRIDGE_W9968CF },
50010c0d06caSMauro Carvalho Chehab {USB_DEVICE(0x8020, 0xef04), .driver_info = BRIDGE_OVFX2 },
50020c0d06caSMauro Carvalho Chehab {}
50030c0d06caSMauro Carvalho Chehab };
50040c0d06caSMauro Carvalho Chehab
50050c0d06caSMauro Carvalho Chehab MODULE_DEVICE_TABLE(usb, device_table);
50060c0d06caSMauro Carvalho Chehab
50070c0d06caSMauro Carvalho Chehab /* -- device connect -- */
sd_probe(struct usb_interface * intf,const struct usb_device_id * id)50080c0d06caSMauro Carvalho Chehab static int sd_probe(struct usb_interface *intf,
50090c0d06caSMauro Carvalho Chehab const struct usb_device_id *id)
50100c0d06caSMauro Carvalho Chehab {
50110c0d06caSMauro Carvalho Chehab return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
50120c0d06caSMauro Carvalho Chehab THIS_MODULE);
50130c0d06caSMauro Carvalho Chehab }
50140c0d06caSMauro Carvalho Chehab
50150c0d06caSMauro Carvalho Chehab static struct usb_driver sd_driver = {
50160c0d06caSMauro Carvalho Chehab .name = MODULE_NAME,
50170c0d06caSMauro Carvalho Chehab .id_table = device_table,
50180c0d06caSMauro Carvalho Chehab .probe = sd_probe,
50190c0d06caSMauro Carvalho Chehab .disconnect = gspca_disconnect,
50200c0d06caSMauro Carvalho Chehab #ifdef CONFIG_PM
50210c0d06caSMauro Carvalho Chehab .suspend = gspca_suspend,
50220c0d06caSMauro Carvalho Chehab .resume = gspca_resume,
50230c0d06caSMauro Carvalho Chehab .reset_resume = gspca_resume,
50240c0d06caSMauro Carvalho Chehab #endif
50250c0d06caSMauro Carvalho Chehab };
50260c0d06caSMauro Carvalho Chehab
50270c0d06caSMauro Carvalho Chehab module_usb_driver(sd_driver);
50280c0d06caSMauro Carvalho Chehab
50290c0d06caSMauro Carvalho Chehab module_param(frame_rate, int, 0644);
50300c0d06caSMauro Carvalho Chehab MODULE_PARM_DESC(frame_rate, "Frame rate (5, 10, 15, 20 or 30 fps)");
5031