// SPDX-License-Identifier: GPL-2.0-or-later /* * OV519 driver * * Copyright (C) 2008-2011 Jean-François Moine <moinejf@free.fr> * Copyright (C) 2009 Hans de Goede <hdegoede@redhat.com> * * This module is adapted from the ov51x-jpeg package, which itself * was adapted from the ov511 driver. * * Original copyright for the ov511 driver is: * * Copyright (c) 1999-2006 Mark W. McClelland * Support for OV519, OV8610 Copyright (c) 2003 Joerg Heckenbach * Many improvements by Bret Wallach <bwallac1@san.rr.com> * Color fixes by by Orion Sky Lawlor <olawlor@acm.org> (2/26/2000) * OV7620 fixes by Charl P. Botha <cpbotha@ieee.org> * Changes by Claudio Matsuoka <claudio@conectiva.com> * * ov51x-jpeg original copyright is: * * Copyright (c) 2004-2007 Romain Beauxis <toots@rastageeks.org> * Support for OV7670 sensors was contributed by Sam Skipsey <aoanla@yahoo.com>
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#define MODULE_NAME "ov519"
#include <linux/input.h> #include"gspca.h"
/* The jpeg_hdr is used by w996Xcf only */ /* The CONEX_CAM define for jpeg.h needs renaming, now its used here too */ #define CONEX_CAM #include"jpeg.h"
MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
MODULE_DESCRIPTION("OV519 USB Camera Driver");
MODULE_LICENSE("GPL");
/* global parameters */ staticint frame_rate;
/* Number of times to retry a failed I2C transaction. Increase this if you
* are getting "Failed to read sensor ID..." */ staticint i2c_detect_tries = 10;
/* ov519 device descriptor */ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */
/* Note this is a bit of a hack, but the w9968cf driver needs the code for all the ov sensors which is already present here. When we have the time we
really should move the sensor drivers to v4l2 sub drivers. */ #include"w996Xcf.c"
/*#define OV511_ENDPOINT_ADDRESS 1 * Isoc endpoint number */
/* * The FX2 chip does not give us a zero length read at end of frame. * It does, however, give a short read at the end of a frame, if * necessary, rather than run two frames together. * * By choosing the right bulk transfer size, we are guaranteed to always * get a short read for the last read of each frame. Frame sizes are * always a composite number (width * height, or a multiple) so if we * choose a prime number, we are guaranteed that the last read of a * frame will be short. * * But it isn't that easy: the 2.6 kernel requires a multiple of 4KB, * otherwise EOVERFLOW "babbling" errors occur. I have not been able * to figure out why. [PMiller] * * The constant (13 * 4096) is the largest "prime enough" number less than 64KB. * * It isn't enough to know the number of bytes per frame, in case we * have data dropouts or buffer overruns (even though the FX2 double * buffers, there are some pretty strict real time constraints for * isochronous transfer for larger frame sizes).
*/ /*jfm: this value does not work for 800x600 - see isoc_init */ #define OVFX2_BULK_SIZE (13 * 4096)
staticconststruct ov_i2c_regvals norm_3620b[] = { /* * From the datasheet: "Note that after writing to register COMH * (0x12) to change the sensor mode, registers related to the * sensor's cropping window will be reset back to their default * values." * * "wait 4096 external clock ... to make sure the sensor is * stable and ready to access registers" i.e. 160us at 24MHz
*/
{ 0x12, 0x80 }, /* COMH reset */
{ 0x12, 0x00 }, /* QXGA, master */
/* * 11 CLKRC "Clock Rate Control" * [7] internal frequency doublers: on * [6] video port mode: master * [5:0] clock divider: 1
*/
{ 0x11, 0x80 },
/* * 0F COMG "Common Control G" * = 66 (0x42) 01000010 * COMG[7] "Optical black output selection" * = 0 (0x00) 0....... "Disable" * COMG[6] "Black level calibrate selection" * = 1 (0x01) .1...... "Use optical black pixels * to calibrate" * COMG[5:4] "Reserved" * = 0 (0x00) ..00.... * COMG[3] "Channel offset adjustment" * = 0 (0x00) ....0... "Disable offset adjustment" * COMG[2] "ADC black level calibration option" * = 0 (0x00) .....0.. "Use B/G line and G/R * line to calibrate each * channel's black level" * COMG[1] "Reserved" * = 1 (0x01) ......1. * COMG[0] "ADC black level calibration enable" * = 0 (0x00) .......0 "Disable"
*/
{ 0x0f, 0x42 },
/* * 14 COMJ "Common Control J" * = 198 (0xC6) 11000110 * COMJ[7:6] "AGC gain ceiling" * = 3 (0x03) 11...... "8x" * COMJ[5:4] "Reserved" * = 0 (0x00) ..00.... * COMJ[3] "Auto banding filter" * = 0 (0x00) ....0... "Banding filter is always * on off depending on * COMI[5] setting" * COMJ[2] "VSYNC drop option" * = 1 (0x01) .....1.. "SYNC is dropped if frame * data is dropped" * COMJ[1] "Frame data drop" * = 1 (0x01) ......1. "Drop frame data if * exposure is not within * tolerance. In AEC mode, * data is normally dropped * when data is out of * range." * COMJ[0] "Reserved" * = 0 (0x00) .......0
*/
{ 0x14, 0xc6 },
{ 0x3d, 0x80 }, /* These next two registers (0x4a, 0x4b) are undocumented.
* They control the color balance */
{ 0x4a, 0x80 },
{ 0x4b, 0x80 },
{ 0x4d, 0xd2 }, /* This reduces noise a bit */
{ 0x4e, 0xc1 },
{ 0x4f, 0x04 }, /* Do 50-53 have any effect? */ /* Toggle 0x12[2] off and on here? */
};
/* 7670. Defaults taken from OmniVision provided data,
* as provided by Jonathan Corbet of OLPC */ staticconststruct ov_i2c_regvals norm_7670[] = {
{ OV7670_R12_COM7, OV7670_COM7_RESET },
{ OV7670_R3A_TSLB, 0x04 }, /* OV */
{ OV7670_R12_COM7, OV7670_COM7_FMT_VGA }, /* VGA */
{ OV7670_R11_CLKRC, 0x01 }, /* * Set the hardware window. These values from OV don't entirely * make sense - hstop is less than hstart. But they work...
*/
{ OV7670_R17_HSTART, 0x13 },
{ OV7670_R18_HSTOP, 0x01 },
{ OV7670_R32_HREF, 0xb6 },
{ OV7670_R19_VSTART, 0x02 },
{ OV7670_R1A_VSTOP, 0x7a },
{ OV7670_R03_VREF, 0x0a },
/* Read from a OV519 register, note not valid for the w9968cf!! */ /* returns: negative is error, pos or zero is data */ staticint reg_r(struct sd *sd, u16 index)
{ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; int ret; int req;
if (sd->gspca_dev.usb_err < 0) return -1;
switch (sd->bridge) { case BRIDGE_OV511: case BRIDGE_OV511PLUS:
req = 3; break; case BRIDGE_OVFX2:
req = 0x0b; break; default:
req = 1;
}
/* Avoid things going to fast for the bridge with a xhci host */
udelay(150);
ret = usb_control_msg(sd->gspca_dev.dev,
usb_rcvctrlpipe(sd->gspca_dev.dev, 0),
req,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, index, sd->gspca_dev.usb_buf, 1, 500);
if (ret >= 0) {
ret = sd->gspca_dev.usb_buf[0];
gspca_dbg(gspca_dev, D_USBI, "GET %02x 0000 %04x %02x\n",
req, index, ret);
} else {
gspca_err(gspca_dev, "reg_r %02x failed %d\n", index, ret);
sd->gspca_dev.usb_err = ret; /* * Make sure the result is zeroed to avoid uninitialized * values.
*/
gspca_dev->usb_buf[0] = 0;
}
return ret;
}
/* Read 8 values from a OV519 register */ staticint reg_r8(struct sd *sd,
u16 index)
{ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; int ret;
if (sd->gspca_dev.usb_err < 0) return -1;
/* Avoid things going to fast for the bridge with a xhci host */
udelay(150);
ret = usb_control_msg(sd->gspca_dev.dev,
usb_rcvctrlpipe(sd->gspca_dev.dev, 0), 1, /* REQ_IO */
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, index, sd->gspca_dev.usb_buf, 8, 500);
if (ret >= 0) {
ret = sd->gspca_dev.usb_buf[0];
} else {
gspca_err(gspca_dev, "reg_r8 %02x failed %d\n", index, ret);
sd->gspca_dev.usb_err = ret; /* * Make sure the buffer is zeroed to avoid uninitialized * values.
*/
memset(gspca_dev->usb_buf, 0, 8);
}
return ret;
}
/* * Writes bits at positions specified by mask to an OV51x reg. Bits that are in * the same position as 1's in "mask" are cleared and set to "value". Bits * that are in the same position as 0's in "mask" are preserved, regardless * of their respective state in "value".
*/ staticvoid reg_w_mask(struct sd *sd,
u16 index,
u8 value,
u8 mask)
{ int ret;
u8 oldval;
if (mask != 0xff) {
value &= mask; /* Enforce mask on value */
ret = reg_r(sd, index); if (ret < 0) return;
oldval = ret & ~mask; /* Clear the masked bits */
value |= oldval; /* Set the desired bits */
}
reg_w(sd, index, value);
}
/* * Writes multiple (n) byte value to a single register. Only valid with certain * registers (0x30 and 0xc4 - 0xce).
*/ staticvoid ov518_reg_w32(struct sd *sd, u16 index, u32 value, int n)
{ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; int ret;
/* Avoid things going to fast for the bridge with a xhci host */
udelay(150);
ret = usb_control_msg(sd->gspca_dev.dev,
usb_sndctrlpipe(sd->gspca_dev.dev, 0), 1/* REG_IO */,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, index,
sd->gspca_dev.usb_buf, n, 500); if (ret < 0) {
gspca_err(gspca_dev, "reg_w32 %02x failed %d\n", index, ret);
sd->gspca_dev.usb_err = ret;
}
}
/* This is needed to make i2c_w() work */
reg_w(sd, R511_I2C_CTL, 0x05);
return value;
}
/* * The OV518 I2C I/O procedure is different, hence, this function. * This is normally only called from i2c_w(). Note that this function * always succeeds regardless of whether the sensor is present and working.
*/ staticvoid ov518_i2c_w(struct sd *sd,
u8 reg,
u8 value)
{ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
/* wait for write complete */
msleep(4);
reg_r8(sd, R518_I2C_CTL);
}
/* * returns: negative is error, pos or zero is data * * The OV518 I2C I/O procedure is different, hence, this function. * This is normally only called from i2c_r(). Note that this function * always succeeds regardless of whether the sensor is present and working.
*/ staticint ov518_i2c_r(struct sd *sd, u8 reg)
{ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; int value;
/* Select camera register */
reg_w(sd, R51x_I2C_SADDR_2, reg);
switch (sd->bridge) { case BRIDGE_OV511: case BRIDGE_OV511PLUS:
ov511_i2c_w(sd, reg, value); break; case BRIDGE_OV518: case BRIDGE_OV518PLUS: case BRIDGE_OV519:
ov518_i2c_w(sd, reg, value); break; case BRIDGE_OVFX2:
ovfx2_i2c_w(sd, reg, value); break; case BRIDGE_W9968CF:
w9968cf_i2c_w(sd, reg, value); break;
}
if (sd->gspca_dev.usb_err >= 0) { /* Up on sensor reset empty the register cache */ if (reg == 0x12 && (value & 0x80))
memset(sd->sensor_reg_cache, -1, sizeof(sd->sensor_reg_cache)); else
sd->sensor_reg_cache[reg] = value;
}
}
staticint i2c_r(struct sd *sd, u8 reg)
{ int ret = -1;
if (sd->sensor_reg_cache[reg] != -1) return sd->sensor_reg_cache[reg];
switch (sd->bridge) { case BRIDGE_OV511: case BRIDGE_OV511PLUS:
ret = ov511_i2c_r(sd, reg); break; case BRIDGE_OV518: case BRIDGE_OV518PLUS: case BRIDGE_OV519:
ret = ov518_i2c_r(sd, reg); break; case BRIDGE_OVFX2:
ret = ovfx2_i2c_r(sd, reg); break; case BRIDGE_W9968CF:
ret = w9968cf_i2c_r(sd, reg); break;
}
if (ret >= 0)
sd->sensor_reg_cache[reg] = ret;
return ret;
}
/* Writes bits at positions specified by mask to an I2C reg. Bits that are in * the same position as 1's in "mask" are cleared and set to "value". Bits * that are in the same position as 0's in "mask" are preserved, regardless * of their respective state in "value".
*/ staticvoid i2c_w_mask(struct sd *sd,
u8 reg,
u8 value,
u8 mask)
{ int rc;
u8 oldval;
value &= mask; /* Enforce mask on value */
rc = i2c_r(sd, reg); if (rc < 0) return;
oldval = rc & ~mask; /* Clear the masked bits */
value |= oldval; /* Set the desired bits */
i2c_w(sd, reg, value);
}
/* Temporarily stops OV511 from functioning. Must do this before changing
* registers while the camera is streaming */ staticinlinevoid ov51x_stop(struct sd *sd)
{ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
gspca_dbg(gspca_dev, D_STREAM, "stopping\n");
sd->stopped = 1; switch (sd->bridge) { case BRIDGE_OV511: case BRIDGE_OV511PLUS:
reg_w(sd, R51x_SYS_RESET, 0x3d); break; case BRIDGE_OV518: case BRIDGE_OV518PLUS:
reg_w_mask(sd, R51x_SYS_RESET, 0x3a, 0x3a); break; case BRIDGE_OV519:
reg_w(sd, OV519_R51_RESET1, 0x0f);
reg_w(sd, OV519_R51_RESET1, 0x00);
reg_w(sd, 0x22, 0x00); /* FRAR */ break; case BRIDGE_OVFX2:
reg_w_mask(sd, 0x0f, 0x00, 0x02); break; case BRIDGE_W9968CF:
reg_w(sd, 0x3c, 0x0a05); /* stop USB transfer */ break;
}
}
/* Restarts OV511 after ov511_stop() is called. Has no effect if it is not
* actually stopped (for performance). */ staticinlinevoid ov51x_restart(struct sd *sd)
{ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
gspca_dbg(gspca_dev, D_STREAM, "restarting\n"); if (!sd->stopped) return;
sd->stopped = 0;
/* Reinitialize the stream */ switch (sd->bridge) { case BRIDGE_OV511: case BRIDGE_OV511PLUS:
reg_w(sd, R51x_SYS_RESET, 0x00); break; case BRIDGE_OV518: case BRIDGE_OV518PLUS:
reg_w(sd, 0x2f, 0x80);
reg_w(sd, R51x_SYS_RESET, 0x00); break; case BRIDGE_OV519:
reg_w(sd, OV519_R51_RESET1, 0x0f);
reg_w(sd, OV519_R51_RESET1, 0x00);
reg_w(sd, 0x22, 0x1d); /* FRAR */ break; case BRIDGE_OVFX2:
reg_w_mask(sd, 0x0f, 0x02, 0x02); break; case BRIDGE_W9968CF:
reg_w(sd, 0x3c, 0x8a05); /* USB FIFO enable */ break;
}
}
/* This does an initial reset of an OmniVision sensor and ensures that I2C * is synchronized. Returns <0 on failure.
*/ staticint init_ov_sensor(struct sd *sd, u8 slave)
{ int i; struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
ov51x_set_slave_ids(sd, slave);
/* Reset the sensor */
i2c_w(sd, 0x12, 0x80);
/* Wait for it to initialize */
msleep(150);
for (i = 0; i < i2c_detect_tries; i++) { if (i2c_r(sd, OV7610_REG_ID_HIGH) == 0x7f &&
i2c_r(sd, OV7610_REG_ID_LOW) == 0xa2) {
gspca_dbg(gspca_dev, D_PROBE, "I2C synced in %d attempt(s)\n",
i); return0;
}
/* Reset the sensor */
i2c_w(sd, 0x12, 0x80);
/* Wait for it to initialize */
msleep(150);
/* Dummy read to sync I2C */ if (i2c_r(sd, 0x00) < 0) return -1;
} return -1;
}
/* Set the read and write slave IDs. The "slave" argument is the write slave, * and the read slave will be set to (slave + 1). * This should not be called from outside the i2c I/O functions. * Sets I2C read and write slave IDs. Returns <0 for error
*/ staticvoid ov51x_set_slave_ids(struct sd *sd,
u8 slave)
{ switch (sd->bridge) { case BRIDGE_OVFX2:
reg_w(sd, OVFX2_I2C_ADDR, slave); return; case BRIDGE_W9968CF:
sd->sensor_addr = slave; return;
}
/**************************************************************************** * * OV511 and sensor configuration *
***************************************************************************/
/* This initializes the OV2x10 / OV3610 / OV3620 / OV9600 */ staticvoid ov_hires_configure(struct sd *sd)
{ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; int high, low;
if (sd->bridge != BRIDGE_OVFX2) {
gspca_err(gspca_dev, "error hires sensors only supported with ovfx2\n"); return;
}
gspca_dbg(gspca_dev, D_PROBE, "starting ov hires configuration\n");
/* Detect sensor (sub)type */
high = i2c_r(sd, 0x0a);
low = i2c_r(sd, 0x0b); /* info("%x, %x", high, low); */ switch (high) { case0x96: switch (low) { case0x40:
gspca_dbg(gspca_dev, D_PROBE, "Sensor is a OV2610\n");
sd->sensor = SEN_OV2610; return; case0x41:
gspca_dbg(gspca_dev, D_PROBE, "Sensor is a OV2610AE\n");
sd->sensor = SEN_OV2610AE; return; case0xb1:
gspca_dbg(gspca_dev, D_PROBE, "Sensor is a OV9600\n");
sd->sensor = SEN_OV9600; return;
} break; case0x36: if ((low & 0x0f) == 0x00) {
gspca_dbg(gspca_dev, D_PROBE, "Sensor is a OV3610\n");
sd->sensor = SEN_OV3610; return;
} break;
}
gspca_err(gspca_dev, "Error unknown sensor type: %02x%02x\n",
high, low);
}
/* This initializes the OV8110, OV8610 sensor. The OV8110 uses * the same register settings as the OV8610, since they are very similar.
*/ staticvoid ov8xx0_configure(struct sd *sd)
{ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; int rc;
/* This initializes the OV7610, OV7620, or OV76BE sensor. The OV76BE uses * the same register settings as the OV7610, since they are very similar.
*/ staticvoid ov7xx0_configure(struct sd *sd)
{ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; int rc, high, low;
/* Ugh. The first two bits are the version bits, but * the entire register value must be used. I guess OVT
* underestimated how many variants they would make. */ switch (rc) { case0x00:
sd->sensor = SEN_OV6630;
pr_warn("WARNING: Sensor is an OV66308. Your camera may have been misdetected in previous driver versions.\n"); break; case0x01:
sd->sensor = SEN_OV6620;
gspca_dbg(gspca_dev, D_PROBE, "Sensor is an OV6620\n"); break; case0x02:
sd->sensor = SEN_OV6630;
gspca_dbg(gspca_dev, D_PROBE, "Sensor is an OV66308AE\n"); break; case0x03:
sd->sensor = SEN_OV66308AF;
gspca_dbg(gspca_dev, D_PROBE, "Sensor is an OV66308AF\n"); break; case0x90:
sd->sensor = SEN_OV6630;
pr_warn("WARNING: Sensor is an OV66307. Your camera may have been misdetected in previous driver versions.\n"); break; default:
gspca_err(gspca_dev, "FATAL: Unknown sensor version: 0x%02x\n",
rc); return;
}
/* Set sensor-specific vars */
sd->sif = 1;
}
/* Turns on or off the LED. Only has an effect with OV511+/OV518(+)/OV519 */ staticvoid ov51x_led_control(struct sd *sd, int on)
{ if (sd->invert_led)
on = !on;
switch (sd->bridge) { /* OV511 has no LED control */ case BRIDGE_OV511PLUS:
reg_w(sd, R511_SYS_LED_CTL, on); break; case BRIDGE_OV518: case BRIDGE_OV518PLUS:
reg_w_mask(sd, R518_GPIO_OUT, 0x02 * on, 0x02); break; case BRIDGE_OV519:
reg_w_mask(sd, OV519_GPIO_DATA_OUT0, on, 1); break;
}
}
/* Note it is important that we clear sd->snapshot_needs_reset, before actually clearing the snapshot state in the bridge
otherwise we might race with the pkt_scan interrupt handler */
sd->snapshot_needs_reset = 0;
switch (sd->bridge) { case BRIDGE_OV511: case BRIDGE_OV511PLUS:
reg_w(sd, R51x_SYS_SNAP, 0x02);
reg_w(sd, R51x_SYS_SNAP, 0x00); break; case BRIDGE_OV518: case BRIDGE_OV518PLUS:
reg_w(sd, R51x_SYS_SNAP, 0x02); /* Reset */
reg_w(sd, R51x_SYS_SNAP, 0x01); /* Enable */ break; case BRIDGE_OV519:
reg_w(sd, R51x_SYS_RESET, 0x40);
reg_w(sd, R51x_SYS_RESET, 0x00); break;
}
}
/* First 5 bits of custom ID reg are a revision ID on OV518 */
sd->revision = reg_r(sd, R51x_SYS_CUST_ID) & 0x1f;
gspca_dbg(gspca_dev, D_PROBE, "Device revision %d\n", sd->revision);
/* this function is called at probe time */ staticint sd_config(struct gspca_dev *gspca_dev, conststruct usb_device_id *id)
{ struct sd *sd = (struct sd *) gspca_dev; struct cam *cam = &gspca_dev->cam;
switch (sd->bridge) { case BRIDGE_OV511: case BRIDGE_OV511PLUS:
cam->cam_mode = ov511_vga_mode;
cam->nmodes = ARRAY_SIZE(ov511_vga_mode); break; case BRIDGE_OV518: case BRIDGE_OV518PLUS:
cam->cam_mode = ov518_vga_mode;
cam->nmodes = ARRAY_SIZE(ov518_vga_mode); break; case BRIDGE_OV519:
cam->cam_mode = ov519_vga_mode;
cam->nmodes = ARRAY_SIZE(ov519_vga_mode); break; case BRIDGE_OVFX2:
cam->cam_mode = ov519_vga_mode;
cam->nmodes = ARRAY_SIZE(ov519_vga_mode);
cam->bulk_size = OVFX2_BULK_SIZE;
cam->bulk_nurbs = MAX_NURBS;
cam->bulk = 1; break; case BRIDGE_W9968CF:
cam->cam_mode = w9968cf_vga_mode;
cam->nmodes = ARRAY_SIZE(w9968cf_vga_mode); break;
}
sd->frame_rate = 15;
return0;
}
/* this function is called at probe and resume time */ staticint sd_init(struct gspca_dev *gspca_dev)
{ struct sd *sd = (struct sd *) gspca_dev; struct cam *cam = &gspca_dev->cam;
switch (sd->bridge) { case BRIDGE_OV511: case BRIDGE_OV511PLUS:
ov511_configure(gspca_dev); break; case BRIDGE_OV518: case BRIDGE_OV518PLUS:
ov518_configure(gspca_dev); break; case BRIDGE_OV519:
ov519_configure(sd); break; case BRIDGE_OVFX2:
ovfx2_configure(sd); break; case BRIDGE_W9968CF:
w9968cf_configure(sd); break;
}
/* The OV519 must be more aggressive about sensor detection since * I2C write will never fail if the sensor is not present. We have
* to try to initialize the sensor to detect its presence */
sd->sensor = -1;
/* Test for 76xx */ if (init_ov_sensor(sd, OV7xx0_SID) >= 0) {
ov7xx0_configure(sd);
/* Test for 6xx0 */
} elseif (init_ov_sensor(sd, OV6xx0_SID) >= 0) {
ov6xx0_configure(sd);
/* Test for 8xx0 */
} elseif (init_ov_sensor(sd, OV8xx0_SID) >= 0) {
ov8xx0_configure(sd);
/* Set up the OV511/OV511+ with the given image parameters. * * Do not put any sensor-specific code in here (including I2C I/O functions)
*/ staticvoid ov511_mode_init_regs(struct sd *sd)
{ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; int hsegs, vsegs, packet_size, fps, needed; int interlaced = 0; struct usb_host_interface *alt; struct usb_interface *intf;
intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt); if (!alt) {
gspca_err(gspca_dev, "Couldn't get altsetting\n");
sd->gspca_dev.usb_err = -EIO; return;
}
if (alt->desc.bNumEndpoints < 1) {
sd->gspca_dev.usb_err = -ENODEV; return;
}
/******** Set the framerate ********/ if (frame_rate > 0)
sd->frame_rate = frame_rate;
switch (sd->sensor) { case SEN_OV6620: /* No framerate control, doesn't like higher rates yet */
sd->clockdiv = 3; break;
/* Note once the FIXME's in mode_init_ov_sensor_regs() are fixed
for more sensors we need to do this for them too */ case SEN_OV7620: case SEN_OV7620AE: case SEN_OV7640: case SEN_OV7648: case SEN_OV76BE: if (sd->gspca_dev.pixfmt.width == 320)
interlaced = 1;
fallthrough; case SEN_OV6630: case SEN_OV7610: case SEN_OV7670: switch (sd->frame_rate) { case30: case25: /* Not enough bandwidth to do 640x480 @ 30 fps */ if (sd->gspca_dev.pixfmt.width != 640) {
sd->clockdiv = 0; break;
} /* For 640x480 case */
fallthrough; default: /* case 20: */ /* case 15: */
sd->clockdiv = 1; break; case10:
sd->clockdiv = 2; break; case5:
sd->clockdiv = 5; break;
} if (interlaced) {
sd->clockdiv = (sd->clockdiv + 1) * 2 - 1; /* Higher then 10 does not work */ if (sd->clockdiv > 10)
sd->clockdiv = 10;
} break;
case SEN_OV8610: /* No framerate control ?? */
sd->clockdiv = 0; break;
}
/* Check if we have enough bandwidth to disable compression */
fps = (interlaced ? 60 : 30) / (sd->clockdiv + 1) + 1;
needed = fps * sd->gspca_dev.pixfmt.width *
sd->gspca_dev.pixfmt.height * 3 / 2; /* 1000 isoc packets/sec */ if (needed > 1000 * packet_size) { /* Enable Y and UV quantization and compression */
reg_w(sd, R511_COMP_EN, 0x07);
reg_w(sd, R511_COMP_LUT_EN, 0x03);
} else {
reg_w(sd, R511_COMP_EN, 0x06);
reg_w(sd, R511_COMP_LUT_EN, 0x00);
}
/* Sets up the OV518/OV518+ with the given image parameters * * OV518 needs a completely different approach, until we can figure out what * the individual registers do. Also, only 15 FPS is supported now. * * Do not put any sensor-specific code in here (including I2C I/O functions)
*/ staticvoid ov518_mode_init_regs(struct sd *sd)
{ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; int hsegs, vsegs, packet_size; struct usb_host_interface *alt; struct usb_interface *intf;
intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt); if (!alt) {
gspca_err(gspca_dev, "Couldn't get altsetting\n");
sd->gspca_dev.usb_err = -EIO; return;
}
if (alt->desc.bNumEndpoints < 1) {
sd->gspca_dev.usb_err = -ENODEV; return;
}
/* Windows driver does this here; who knows why */
reg_w(sd, 0x2f, 0x80);
/******** Set the framerate ********/ if (sd->bridge == BRIDGE_OV518PLUS && sd->revision == 0 &&
sd->sensor == SEN_OV7620AE)
sd->clockdiv = 0; else
sd->clockdiv = 1;
/* Mode independent, but framerate dependent, regs */ /* 0x51: Clock divider; Only works on some cams which use 2 crystals */
reg_w(sd, 0x51, 0x04);
reg_w(sd, 0x22, 0x18);
reg_w(sd, 0x23, 0xff);
if (sd->bridge == BRIDGE_OV518PLUS) { switch (sd->sensor) { case SEN_OV7620AE: /* * HdG: 640x480 needs special handling on device * revision 2, we check for device revision > 0 to * avoid regressions, as we don't know the correct * thing todo for revision 1. * * Also this likely means we don't need to * differentiate between the OV7620 and OV7620AE, * earlier testing hitting this same problem likely * happened to be with revision < 2 cams using an * OV7620 and revision 2 cams using an OV7620AE.
*/ if (sd->revision > 0 &&
sd->gspca_dev.pixfmt.width == 640) {
reg_w(sd, 0x20, 0x60);
reg_w(sd, 0x21, 0x1f);
} else {
reg_w(sd, 0x20, 0x00);
reg_w(sd, 0x21, 0x19);
} break; case SEN_OV7620:
reg_w(sd, 0x20, 0x00);
reg_w(sd, 0x21, 0x19); break; default:
reg_w(sd, 0x21, 0x19);
}
} else
reg_w(sd, 0x71, 0x17); /* Compression-related? */
/* FIXME: Sensor-specific */ /* Bit 5 is what matters here. Of course, it is "reserved" */
i2c_w(sd, 0x54, 0x23);
/* this function works for bridge ov519 and sensors ov7660 and ov7670 only */ staticvoid sethvflip(struct gspca_dev *gspca_dev, s32 hflip, s32 vflip)
{ struct sd *sd = (struct sd *) gspca_dev;
staticvoid set_ov_sensor_window(struct sd *sd)
{ struct gspca_dev *gspca_dev; int qvga, crop; int hwsbase, hwebase, vwsbase, vwebase, hwscale, vwscale;
/* mode setup is fully handled in mode_init_ov_sensor_regs for these */ switch (sd->sensor) { case SEN_OV2610: case SEN_OV2610AE: case SEN_OV3610: case SEN_OV7670: case SEN_OV9600:
mode_init_ov_sensor_regs(sd); return; case SEN_OV7660:
ov519_set_mode(sd);
ov519_set_fr(sd); return;
}
/* The different sensor ICs handle setting up of window differently.
* IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!! */ switch (sd->sensor) { case SEN_OV8610:
hwsbase = 0x1e;
hwebase = 0x1e;
vwsbase = 0x02;
vwebase = 0x02; break; case SEN_OV7610: case SEN_OV76BE:
hwsbase = 0x38;
hwebase = 0x3a;
vwsbase = vwebase = 0x05; break; case SEN_OV6620: case SEN_OV6630: case SEN_OV66308AF:
hwsbase = 0x38;
hwebase = 0x3a;
vwsbase = 0x05;
vwebase = 0x06; if (sd->sensor == SEN_OV66308AF && qvga) /* HDG: this fixes U and V getting swapped */
hwsbase++; if (crop) {
hwsbase += 8;
hwebase += 8;
vwsbase += 11;
vwebase += 11;
} break; case SEN_OV7620: case SEN_OV7620AE:
hwsbase = 0x2f; /* From 7620.SET (spec is wrong) */
hwebase = 0x2f;
vwsbase = vwebase = 0x05; break; case SEN_OV7640: case SEN_OV7648:
hwsbase = 0x1a;
hwebase = 0x1a;
vwsbase = vwebase = 0x03; break; default: return;
}
/* -- start the camera -- */ staticint sd_start(struct gspca_dev *gspca_dev)
{ struct sd *sd = (struct sd *) gspca_dev;
/* Default for most bridges, allow bridge_mode_init_regs to override */
sd->sensor_width = sd->gspca_dev.pixfmt.width;
sd->sensor_height = sd->gspca_dev.pixfmt.height;
switch (sd->bridge) { case BRIDGE_OV511: case BRIDGE_OV511PLUS:
ov511_mode_init_regs(sd); break; case BRIDGE_OV518: case BRIDGE_OV518PLUS:
ov518_mode_init_regs(sd); break; case BRIDGE_OV519:
ov519_mode_init_regs(sd); break; /* case BRIDGE_OVFX2: nothing to do */ case BRIDGE_W9968CF:
w9968cf_mode_init_regs(sd); break;
}
set_ov_sensor_window(sd);
/* Force clear snapshot state in case the snapshot button was
pressed while we weren't streaming */
sd->snapshot_needs_reset = 1;
sd_reset_snapshot(gspca_dev);
if (!sd->gspca_dev.present) return; if (sd->bridge == BRIDGE_W9968CF)
w9968cf_stop0(sd);
#if IS_ENABLED(CONFIG_INPUT) /* If the last button state is pressed, release it now! */ if (sd->snapshot_pressed) {
input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
input_sync(gspca_dev->input_dev);
sd->snapshot_pressed = 0;
} #endif if (sd->bridge == BRIDGE_OV519)
reg_w(sd, OV519_R57_SNAPSHOT, 0x23);
}
if (sd->snapshot_pressed != state) { #if IS_ENABLED(CONFIG_INPUT)
input_report_key(gspca_dev->input_dev, KEY_CAMERA, state);
input_sync(gspca_dev->input_dev); #endif if (state)
sd->snapshot_needs_reset = 1;
sd->snapshot_pressed = state;
} else { /* On the ov511 / ov519 we need to reset the button state multiple times, as resetting does not work as long as the
button stays pressed */ switch (sd->bridge) { case BRIDGE_OV511: case BRIDGE_OV511PLUS: case BRIDGE_OV519: if (state)
sd->snapshot_needs_reset = 1; break;
}
}
}
/* A false positive here is likely, until OVT gives me
* the definitive SOF/EOF format */ if ((!(data[0] | data[1] | data[2] | data[3] | data[5])) && data[6]) {
ov51x_handle_button(gspca_dev, (data[6] >> 1) & 1);
gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0);
sd->packet_nr = 0;
}
if (gspca_dev->last_packet_type == DISCARD_PACKET) return;
/* Does this device use packet numbers ? */ if (len & 7) {
len--; if (sd->packet_nr == data[len])
sd->packet_nr++; /* The last few packets of the frame (which are all 0's except that they may contain part of the footer), are
numbered 0 */ elseif (sd->packet_nr == 0 || data[len]) {
gspca_err(gspca_dev, "Invalid packet nr: %d (expect: %d)\n",
(int)data[len], (int)sd->packet_nr);
gspca_dev->last_packet_type = DISCARD_PACKET; return;
}
}
/* A short read signals EOF */ if (len < gspca_dev->cam.bulk_size) { /* If the frame is short, and it is one of the first ones
the sensor and bridge are still syncing, so drop it. */ if (sd->first_frame) {
sd->first_frame--; if (gspca_dev->image_len <
sd->gspca_dev.pixfmt.width *
sd->gspca_dev.pixfmt.height)
gspca_dev->last_packet_type = DISCARD_PACKET;
}
gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0);
}
}
switch (sd->sensor) { case SEN_OV8610: case SEN_OV7610: case SEN_OV76BE: case SEN_OV6620: case SEN_OV6630: case SEN_OV66308AF: case SEN_OV7640: case SEN_OV7648:
i2c_w(sd, OV7610_REG_BRT, val); break; case SEN_OV7620: case SEN_OV7620AE:
i2c_w(sd, OV7610_REG_BRT, val); break; case SEN_OV7660:
write_i2c_regvals(sd, brit_7660[val],
ARRAY_SIZE(brit_7660[0])); break; case SEN_OV7670: /*win trace
* i2c_w_mask(sd, OV7670_R13_COM8, 0, OV7670_COM8_AEC); */
i2c_w(sd, OV7670_R55_BRIGHT, ov7670_abs_to_sm(val)); break;
}
}
switch (sd->sensor) { case SEN_OV7610: case SEN_OV6620:
i2c_w(sd, OV7610_REG_CNT, val); break; case SEN_OV6630: case SEN_OV66308AF:
i2c_w_mask(sd, OV7610_REG_CNT, val >> 4, 0x0f); break; case SEN_OV8610: { staticconst u8 ctab[] = { 0x03, 0x09, 0x0b, 0x0f, 0x53, 0x6f, 0x35, 0x7f
};
/* Use Y gamma control instead. Bit 0 enables it. */
i2c_w(sd, 0x64, ctab[val >> 5]); break;
} case SEN_OV7620: case SEN_OV7620AE: { staticconst u8 ctab[] = { 0x01, 0x05, 0x09, 0x11, 0x15, 0x35, 0x37, 0x57, 0x5b, 0xa5, 0xa7, 0xc7, 0xc9, 0xcf, 0xef, 0xff
};
/* Use Y gamma control instead. Bit 0 enables it. */
i2c_w(sd, 0x64, ctab[val >> 4]); break;
} case SEN_OV7660:
write_i2c_regvals(sd, contrast_7660[val],
ARRAY_SIZE(contrast_7660[0])); break; case SEN_OV7670: /* check that this isn't just the same as ov7610 */
i2c_w(sd, OV7670_R56_CONTRAS, val >> 1); break;
}
}
switch (sd->sensor) { case SEN_OV8610: case SEN_OV7610: case SEN_OV76BE: case SEN_OV6620: case SEN_OV6630: case SEN_OV66308AF:
i2c_w(sd, OV7610_REG_SAT, val); break; case SEN_OV7620: case SEN_OV7620AE: /* Use UV gamma control instead. Bits 0 & 7 are reserved. */ /* rc = ov_i2c_write(sd->dev, 0x62, (val >> 9) & 0x7e); if (rc < 0)
goto out; */
i2c_w(sd, OV7610_REG_SAT, val); break; case SEN_OV7640: case SEN_OV7648:
i2c_w(sd, OV7610_REG_SAT, val & 0xf0); break; case SEN_OV7660:
write_i2c_regvals(sd, colors_7660[val],
ARRAY_SIZE(colors_7660[0])); break; case SEN_OV7670: /* supported later once I work out how to do it
* transparently fail now! */ /* set REG_COM13 values for UV sat auto mode */ break;
}
}
switch (ctrl->id) { case V4L2_CID_BRIGHTNESS:
setbrightness(gspca_dev, ctrl->val); break; case V4L2_CID_CONTRAST:
setcontrast(gspca_dev, ctrl->val); break; case V4L2_CID_POWER_LINE_FREQUENCY:
setfreq(gspca_dev, ctrl->val); break; case V4L2_CID_AUTOBRIGHTNESS: if (ctrl->is_new)
setautobright(gspca_dev, ctrl->val); if (!ctrl->val && sd->brightness->is_new)
setbrightness(gspca_dev, sd->brightness->val); break; case V4L2_CID_SATURATION:
setcolors(gspca_dev, ctrl->val); break; case V4L2_CID_HFLIP:
sethvflip(gspca_dev, ctrl->val, sd->vflip->val); break; case V4L2_CID_AUTOGAIN: if (ctrl->is_new)
setautogain(gspca_dev, ctrl->val); if (!ctrl->val && gspca_dev->exposure->is_new)
setexposure(gspca_dev, gspca_dev->exposure->val); break; case V4L2_CID_JPEG_COMPRESSION_QUALITY: return -EBUSY; /* Should never happen, as we grab the ctrl */
} return gspca_dev->usb_err;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.