mirror of https://gitee.com/openkylin/linux.git
V4L/DVB (5062): SN9C102 driver updates
- Add support for SN9C105 and SN9C120 - Add some more USB device identifiers - Add support for OV7660 - Implement audio ioctl's and VIDIOC_ENUM_FRAMESIZES - Add preliminary support for 0x0c45/0x6007 - Documentation updates - Generic improvements Signed-off-by: Luca Risolia <luca.risolia@studio.unibo.it> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
This commit is contained in:
parent
19790db00b
commit
f327ebbd00
|
@ -1,5 +1,5 @@
|
|||
|
||||
SN9C10x PC Camera Controllers
|
||||
SN9C1xx PC Camera Controllers
|
||||
Driver for Linux
|
||||
=============================
|
||||
|
||||
|
@ -53,20 +53,14 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|||
|
||||
4. Overview and features
|
||||
========================
|
||||
This driver attempts to support the video interface of the devices mounting the
|
||||
SONiX SN9C101, SN9C102 and SN9C103 PC Camera Controllers.
|
||||
|
||||
It's worth to note that SONiX has never collaborated with the author during the
|
||||
development of this project, despite several requests for enough detailed
|
||||
specifications of the register tables, compression engine and video data format
|
||||
of the above chips. Nevertheless, these informations are no longer necessary,
|
||||
because all the aspects related to these chips are known and have been
|
||||
described in detail in this documentation.
|
||||
This driver attempts to support the video interface of the devices assembling
|
||||
the SONiX SN9C101, SN9C102, SN9C103, SN9C105 and SN9C120 PC Camera Controllers
|
||||
("SN9C1xx" from now on).
|
||||
|
||||
The driver relies on the Video4Linux2 and USB core modules. It has been
|
||||
designed to run properly on SMP systems as well.
|
||||
|
||||
The latest version of the SN9C10x driver can be found at the following URL:
|
||||
The latest version of the SN9C1xx driver can be found at the following URL:
|
||||
http://www.linux-projects.org/
|
||||
|
||||
Some of the features of the driver are:
|
||||
|
@ -85,11 +79,11 @@ Some of the features of the driver are:
|
|||
high compression quality (see also "Notes for V4L2 application developers"
|
||||
and "Video frame formats" paragraphs);
|
||||
- full support for the capabilities of many of the possible image sensors that
|
||||
can be connected to the SN9C10x bridges, including, for instance, red, green,
|
||||
can be connected to the SN9C1xx bridges, including, for instance, red, green,
|
||||
blue and global gain adjustments and exposure (see "Supported devices"
|
||||
paragraph for details);
|
||||
- use of default color settings for sunlight conditions;
|
||||
- dynamic I/O interface for both SN9C10x and image sensor control and
|
||||
- dynamic I/O interface for both SN9C1xx and image sensor control and
|
||||
monitoring (see "Optional device control through 'sysfs'" paragraph);
|
||||
- dynamic driver control thanks to various module parameters (see "Module
|
||||
parameters" paragraph);
|
||||
|
@ -130,8 +124,8 @@ necessary:
|
|||
CONFIG_USB_UHCI_HCD=m
|
||||
CONFIG_USB_OHCI_HCD=m
|
||||
|
||||
The SN9C103 controller also provides a built-in microphone interface. It is
|
||||
supported by the USB Audio driver thanks to the ALSA API:
|
||||
The SN9C103, SN9c105 and SN9C120 controllers also provide a built-in microphone
|
||||
interface. It is supported by the USB Audio driver thanks to the ALSA API:
|
||||
|
||||
# Sound
|
||||
#
|
||||
|
@ -155,18 +149,27 @@ And finally:
|
|||
6. Module loading
|
||||
=================
|
||||
To use the driver, it is necessary to load the "sn9c102" module into memory
|
||||
after every other module required: "videodev", "usbcore" and, depending on
|
||||
the USB host controller you have, "ehci-hcd", "uhci-hcd" or "ohci-hcd".
|
||||
after every other module required: "videodev", "v4l2_common", "compat_ioctl32",
|
||||
"usbcore" and, depending on the USB host controller you have, "ehci-hcd",
|
||||
"uhci-hcd" or "ohci-hcd".
|
||||
|
||||
Loading can be done as shown below:
|
||||
|
||||
[root@localhost home]# modprobe sn9c102
|
||||
|
||||
At this point the devices should be recognized. You can invoke "dmesg" to
|
||||
analyze kernel messages and verify that the loading process has gone well:
|
||||
Note that the module is called "sn9c102" for historic reasons, althought it
|
||||
does not just support the SN9C102.
|
||||
|
||||
At this point all the devices supported by the driver and connected to the USB
|
||||
ports should be recognized. You can invoke "dmesg" to analyze kernel messages
|
||||
and verify that the loading process has gone well:
|
||||
|
||||
[user@localhost home]$ dmesg
|
||||
|
||||
or, to isolate all the kernel messages generated by the driver:
|
||||
|
||||
[user@localhost home]$ dmesg | grep sn9c102
|
||||
|
||||
|
||||
7. Module parameters
|
||||
====================
|
||||
|
@ -198,10 +201,11 @@ Default: 0
|
|||
-------------------------------------------------------------------------------
|
||||
Name: frame_timeout
|
||||
Type: uint array (min = 0, max = 64)
|
||||
Syntax: <n[,...]>
|
||||
Description: Timeout for a video frame in seconds. This parameter is
|
||||
specific for each detected camera. This parameter can be
|
||||
changed at runtime thanks to the /sys filesystem interface.
|
||||
Syntax: <0|n[,...]>
|
||||
Description: Timeout for a video frame in seconds before returning an I/O
|
||||
error; 0 for infinity. This parameter is specific for each
|
||||
detected camera and can be changed at runtime thanks to the
|
||||
/sys filesystem interface.
|
||||
Default: 2
|
||||
-------------------------------------------------------------------------------
|
||||
Name: debug
|
||||
|
@ -223,20 +227,21 @@ Default: 2
|
|||
8. Optional device control through "sysfs" [1]
|
||||
==========================================
|
||||
If the kernel has been compiled with the CONFIG_VIDEO_ADV_DEBUG option enabled,
|
||||
it is possible to read and write both the SN9C10x and the image sensor
|
||||
it is possible to read and write both the SN9C1xx and the image sensor
|
||||
registers by using the "sysfs" filesystem interface.
|
||||
|
||||
Every time a supported device is recognized, a write-only file named "green" is
|
||||
created in the /sys/class/video4linux/videoX directory. You can set the green
|
||||
channel's gain by writing the desired value to it. The value may range from 0
|
||||
to 15 for SN9C101 or SN9C102 bridges, from 0 to 127 for SN9C103 bridges.
|
||||
Similarly, only for SN9C103 controllers, blue and red gain control files are
|
||||
available in the same directory, for which accepted values may range from 0 to
|
||||
127.
|
||||
to 15 for the SN9C101 or SN9C102 bridges, from 0 to 127 for the SN9C103,
|
||||
SN9C105 and SN9C120 bridges.
|
||||
Similarly, only for the SN9C103, SN9C105 and SN9120 controllers, blue and red
|
||||
gain control files are available in the same directory, for which accepted
|
||||
values may range from 0 to 127.
|
||||
|
||||
There are other four entries in the directory above for each registered camera:
|
||||
"reg", "val", "i2c_reg" and "i2c_val". The first two files control the
|
||||
SN9C10x bridge, while the other two control the sensor chip. "reg" and
|
||||
SN9C1xx bridge, while the other two control the sensor chip. "reg" and
|
||||
"i2c_reg" hold the values of the current register index where the following
|
||||
reading/writing operations are addressed at through "val" and "i2c_val". Their
|
||||
use is not intended for end-users. Note that "i2c_reg" and "i2c_val" will not
|
||||
|
@ -259,61 +264,84 @@ Now let's set the green gain's register of the SN9C101 or SN9C102 chips to 2:
|
|||
[root@localhost #] echo 0x11 > reg
|
||||
[root@localhost #] echo 2 > val
|
||||
|
||||
Note that the SN9C10x always returns 0 when some of its registers are read.
|
||||
Note that the SN9C1xx always returns 0 when some of its registers are read.
|
||||
To avoid race conditions, all the I/O accesses to the above files are
|
||||
serialized.
|
||||
|
||||
The sysfs interface also provides the "frame_header" entry, which exports the
|
||||
frame header of the most recent requested and captured video frame. The header
|
||||
is always 18-bytes long and is appended to every video frame by the SN9C10x
|
||||
is always 18-bytes long and is appended to every video frame by the SN9C1xx
|
||||
controllers. As an example, this additional information can be used by the user
|
||||
application for implementing auto-exposure features via software.
|
||||
|
||||
The following table describes the frame header:
|
||||
The following table describes the frame header exported by the SN9C101 and
|
||||
SN9C102:
|
||||
|
||||
Byte # Value Description
|
||||
------ ----- -----------
|
||||
0x00 0xFF Frame synchronisation pattern.
|
||||
0x01 0xFF Frame synchronisation pattern.
|
||||
0x02 0x00 Frame synchronisation pattern.
|
||||
0x03 0xC4 Frame synchronisation pattern.
|
||||
0x04 0xC4 Frame synchronisation pattern.
|
||||
0x05 0x96 Frame synchronisation pattern.
|
||||
0x06 0xXX Unknown meaning. The exact value depends on the chip;
|
||||
possible values are 0x00, 0x01 and 0x20.
|
||||
0x07 0xXX Variable value, whose bits are ff00uzzc, where ff is a
|
||||
frame counter, u is unknown, zz is a size indicator
|
||||
(00 = VGA, 01 = SIF, 10 = QSIF) and c stands for
|
||||
"compression enabled" (1 = yes, 0 = no).
|
||||
0x08 0xXX Brightness sum inside Auto-Exposure area (low-byte).
|
||||
0x09 0xXX Brightness sum inside Auto-Exposure area (high-byte).
|
||||
For a pure white image, this number will be equal to 500
|
||||
times the area of the specified AE area. For images
|
||||
that are not pure white, the value scales down according
|
||||
to relative whiteness.
|
||||
0x0A 0xXX Brightness sum outside Auto-Exposure area (low-byte).
|
||||
0x0B 0xXX Brightness sum outside Auto-Exposure area (high-byte).
|
||||
For a pure white image, this number will be equal to 125
|
||||
times the area outside of the specified AE area. For
|
||||
images that are not pure white, the value scales down
|
||||
according to relative whiteness.
|
||||
according to relative whiteness.
|
||||
Byte # Value or bits Description
|
||||
------ ------------- -----------
|
||||
0x00 0xFF Frame synchronisation pattern
|
||||
0x01 0xFF Frame synchronisation pattern
|
||||
0x02 0x00 Frame synchronisation pattern
|
||||
0x03 0xC4 Frame synchronisation pattern
|
||||
0x04 0xC4 Frame synchronisation pattern
|
||||
0x05 0x96 Frame synchronisation pattern
|
||||
0x06 [3:0] Read channel gain control = (1+R_GAIN/8)
|
||||
[7:4] Blue channel gain control = (1+B_GAIN/8)
|
||||
0x07 [ 0 ] Compression mode. 0=No compression, 1=Compression enabled
|
||||
[2:1] Maximum scale factor for compression
|
||||
[ 3 ] 1 = USB fifo(2K bytes) is full
|
||||
[ 4 ] 1 = Digital gain is finish
|
||||
[ 5 ] 1 = Exposure is finish
|
||||
[7:6] Frame index
|
||||
0x08 [7:0] Y sum inside Auto-Exposure area (low-byte)
|
||||
0x09 [7:0] Y sum inside Auto-Exposure area (high-byte)
|
||||
where Y sum = (R/4 + 5G/16 + B/8) / 32
|
||||
0x0A [7:0] Y sum outside Auto-Exposure area (low-byte)
|
||||
0x0B [7:0] Y sum outside Auto-Exposure area (high-byte)
|
||||
where Y sum = (R/4 + 5G/16 + B/8) / 128
|
||||
0x0C 0xXX Not used
|
||||
0x0D 0xXX Not used
|
||||
0x0E 0xXX Not used
|
||||
0x0F 0xXX Not used
|
||||
0x10 0xXX Not used
|
||||
0x11 0xXX Not used
|
||||
|
||||
The following bytes are used by the SN9C103 bridge only:
|
||||
The following table describes the frame header exported by the SN9C103:
|
||||
|
||||
0x0C 0xXX Unknown meaning
|
||||
0x0D 0xXX Unknown meaning
|
||||
0x0E 0xXX Unknown meaning
|
||||
0x0F 0xXX Unknown meaning
|
||||
0x10 0xXX Unknown meaning
|
||||
0x11 0xXX Unknown meaning
|
||||
Byte # Value or bits Description
|
||||
------ ------------- -----------
|
||||
0x00 0xFF Frame synchronisation pattern
|
||||
0x01 0xFF Frame synchronisation pattern
|
||||
0x02 0x00 Frame synchronisation pattern
|
||||
0x03 0xC4 Frame synchronisation pattern
|
||||
0x04 0xC4 Frame synchronisation pattern
|
||||
0x05 0x96 Frame synchronisation pattern
|
||||
0x06 [6:0] Read channel gain control = (1/2+R_GAIN/64)
|
||||
0x07 [6:0] Blue channel gain control = (1/2+B_GAIN/64)
|
||||
[7:4]
|
||||
0x08 [ 0 ] Compression mode. 0=No compression, 1=Compression enabled
|
||||
[2:1] Maximum scale factor for compression
|
||||
[ 3 ] 1 = USB fifo(2K bytes) is full
|
||||
[ 4 ] 1 = Digital gain is finish
|
||||
[ 5 ] 1 = Exposure is finish
|
||||
[7:6] Frame index
|
||||
0x09 [7:0] Y sum inside Auto-Exposure area (low-byte)
|
||||
0x0A [7:0] Y sum inside Auto-Exposure area (high-byte)
|
||||
where Y sum = (R/4 + 5G/16 + B/8) / 32
|
||||
0x0B [7:0] Y sum outside Auto-Exposure area (low-byte)
|
||||
0x0C [7:0] Y sum outside Auto-Exposure area (high-byte)
|
||||
where Y sum = (R/4 + 5G/16 + B/8) / 128
|
||||
0x0D [1:0] Audio frame number
|
||||
[ 2 ] 1 = Audio is recording
|
||||
0x0E [7:0] Audio summation (low-byte)
|
||||
0x0F [7:0] Audio summation (high-byte)
|
||||
0x10 [7:0] Audio sample count
|
||||
0x11 [7:0] Audio peak data in audio frame
|
||||
|
||||
The AE area (sx, sy, ex, ey) in the active window can be set by programming the
|
||||
registers 0x1c, 0x1d, 0x1e and 0x1f of the SN9C10x controllers, where one unit
|
||||
registers 0x1c, 0x1d, 0x1e and 0x1f of the SN9C1xx controllers, where one unit
|
||||
corresponds to 32 pixels.
|
||||
|
||||
[1] Part of the meaning of the frame header has been documented by Bertrik
|
||||
Sikken.
|
||||
[1] The frame headers exported by the SN9C105 and SN9C120 are not described.
|
||||
|
||||
|
||||
9. Supported devices
|
||||
|
@ -323,15 +351,19 @@ here. They have never collaborated with the author, so no advertising.
|
|||
|
||||
From the point of view of a driver, what unambiguously identify a device are
|
||||
its vendor and product USB identifiers. Below is a list of known identifiers of
|
||||
devices mounting the SN9C10x PC camera controllers:
|
||||
devices assembling the SN9C1xx PC camera controllers:
|
||||
|
||||
Vendor ID Product ID
|
||||
--------- ----------
|
||||
0x0471 0x0327
|
||||
0x0471 0x0328
|
||||
0x0c45 0x6001
|
||||
0x0c45 0x6005
|
||||
0x0c45 0x6007
|
||||
0x0c45 0x6009
|
||||
0x0c45 0x600d
|
||||
0x0c45 0x6011
|
||||
0x0c45 0x6019
|
||||
0x0c45 0x6024
|
||||
0x0c45 0x6025
|
||||
0x0c45 0x6028
|
||||
|
@ -342,6 +374,7 @@ Vendor ID Product ID
|
|||
0x0c45 0x602d
|
||||
0x0c45 0x602e
|
||||
0x0c45 0x6030
|
||||
0x0c45 0x603f
|
||||
0x0c45 0x6080
|
||||
0x0c45 0x6082
|
||||
0x0c45 0x6083
|
||||
|
@ -368,24 +401,40 @@ Vendor ID Product ID
|
|||
0x0c45 0x60bb
|
||||
0x0c45 0x60bc
|
||||
0x0c45 0x60be
|
||||
0x0c45 0x60c0
|
||||
0x0c45 0x60c8
|
||||
0x0c45 0x60cc
|
||||
0x0c45 0x60ea
|
||||
0x0c45 0x60ec
|
||||
0x0c45 0x60fa
|
||||
0x0c45 0x60fb
|
||||
0x0c45 0x60fc
|
||||
0x0c45 0x60fe
|
||||
0x0c45 0x6130
|
||||
0x0c45 0x613a
|
||||
0x0c45 0x613b
|
||||
0x0c45 0x613c
|
||||
0x0c45 0x613e
|
||||
|
||||
The list above does not imply that all those devices work with this driver: up
|
||||
until now only the ones that mount the following image sensors are supported;
|
||||
kernel messages will always tell you whether this is the case:
|
||||
until now only the ones that assemble the following image sensors are
|
||||
supported; kernel messages will always tell you whether this is the case (see
|
||||
"Module loading" paragraph):
|
||||
|
||||
Model Manufacturer
|
||||
----- ------------
|
||||
HV7131D Hynix Semiconductor, Inc.
|
||||
MI-0343 Micron Technology, Inc.
|
||||
OV7630 OmniVision Technologies, Inc.
|
||||
OV7660 OmniVision Technologies, Inc.
|
||||
PAS106B PixArt Imaging, Inc.
|
||||
PAS202BCA PixArt Imaging, Inc.
|
||||
PAS202BCB PixArt Imaging, Inc.
|
||||
TAS5110C1B Taiwan Advanced Sensor Corporation
|
||||
TAS5130D1B Taiwan Advanced Sensor Corporation
|
||||
|
||||
All the available control settings of each image sensor are supported through
|
||||
the V4L2 interface.
|
||||
Some of the available control settings of each image sensor are supported
|
||||
through the V4L2 interface.
|
||||
|
||||
Donations of new models for further testing and support would be much
|
||||
appreciated. Non-available hardware will not be supported by the author of this
|
||||
|
@ -429,12 +478,15 @@ supplied by this driver).
|
|||
|
||||
11. Video frame formats [1]
|
||||
=======================
|
||||
The SN9C10x PC Camera Controllers can send images in two possible video
|
||||
formats over the USB: either native "Sequential RGB Bayer" or Huffman
|
||||
compressed. The latter is used to achieve high frame rates. The current video
|
||||
format may be selected or queried from the user application by calling the
|
||||
VIDIOC_S_FMT or VIDIOC_G_FMT ioctl's, as described in the V4L2 API
|
||||
specifications.
|
||||
The SN9C1xx PC Camera Controllers can send images in two possible video
|
||||
formats over the USB: either native "Sequential RGB Bayer" or compressed.
|
||||
The compression is used to achieve high frame rates. With regard to the
|
||||
SN9C101, SN9C102 and SN9C103, the compression is based on the Huffman encoding
|
||||
algorithm described below, while the SN9C105 and SN9C120 the compression is
|
||||
based on the JPEG standard.
|
||||
The current video format may be selected or queried from the user application
|
||||
by calling the VIDIOC_S_FMT or VIDIOC_G_FMT ioctl's, as described in the V4L2
|
||||
API specifications.
|
||||
|
||||
The name "Sequential Bayer" indicates the organization of the red, green and
|
||||
blue pixels in one video frame. Each pixel is associated with a 8-bit long
|
||||
|
@ -447,14 +499,14 @@ G[m] R[m+1] G[m+2] R[m+2] ... G[2m-2] R[2m-1]
|
|||
... G[n(m-2)] R[n(m-1)]
|
||||
|
||||
The above matrix also represents the sequential or progressive read-out mode of
|
||||
the (n, m) Bayer color filter array used in many CCD/CMOS image sensors.
|
||||
the (n, m) Bayer color filter array used in many CCD or CMOS image sensors.
|
||||
|
||||
One compressed video frame consists of a bitstream that encodes for every R, G,
|
||||
or B pixel the difference between the value of the pixel itself and some
|
||||
reference pixel value. Pixels are organised in the Bayer pattern and the Bayer
|
||||
sub-pixels are tracked individually and alternatingly. For example, in the
|
||||
first line values for the B and G1 pixels are alternatingly encoded, while in
|
||||
the second line values for the G2 and R pixels are alternatingly encoded.
|
||||
The Huffman compressed video frame consists of a bitstream that encodes for
|
||||
every R, G, or B pixel the difference between the value of the pixel itself and
|
||||
some reference pixel value. Pixels are organised in the Bayer pattern and the
|
||||
Bayer sub-pixels are tracked individually and alternatingly. For example, in
|
||||
the first line values for the B and G1 pixels are alternatingly encoded, while
|
||||
in the second line values for the G2 and R pixels are alternatingly encoded.
|
||||
|
||||
The pixel reference value is calculated as follows:
|
||||
- the 4 top left pixels are encoded in raw uncompressed 8-bit format;
|
||||
|
@ -470,8 +522,9 @@ The pixel reference value is calculated as follows:
|
|||
decoding.
|
||||
|
||||
The algorithm purely describes the conversion from compressed Bayer code used
|
||||
in the SN9C10x chips to uncompressed Bayer. Additional steps are required to
|
||||
convert this to a color image (i.e. a color interpolation algorithm).
|
||||
in the SN9C101, SN9C102 and SN9C103 chips to uncompressed Bayer. Additional
|
||||
steps are required to convert this to a color image (i.e. a color interpolation
|
||||
algorithm).
|
||||
|
||||
The following Huffman codes have been found:
|
||||
0: +0 (relative to reference pixel value)
|
||||
|
@ -506,13 +559,18 @@ order):
|
|||
- Philippe Coval for having helped testing the PAS202BCA image sensor;
|
||||
- Joao Rodrigo Fuzaro, Joao Limirio, Claudio Filho and Caio Begotti for the
|
||||
donation of a webcam;
|
||||
- Dennis Heitmann for the donation of a webcam;
|
||||
- Jon Hollstrom for the donation of a webcam;
|
||||
- Nick McGill for the donation of a webcam;
|
||||
- Carlos Eduardo Medaglia Dyonisio, who added the support for the PAS202BCB
|
||||
image sensor;
|
||||
- Stefano Mozzi, who donated 45 EU;
|
||||
- Andrew Pearce for the donation of a webcam;
|
||||
- John Pullan for the donation of a webcam;
|
||||
- Bertrik Sikken, who reverse-engineered and documented the Huffman compression
|
||||
algorithm used in the SN9C10x controllers and implemented the first decoder;
|
||||
algorithm used in the SN9C101, SN9C102 and SN9C103 controllers and
|
||||
implemented the first decoder;
|
||||
- Mizuno Takafumi for the donation of a webcam;
|
||||
- an "anonymous" donator (who didn't want his name to be revealed) for the
|
||||
donation of a webcam.
|
||||
- an anonymous donator for the donation of four webcams.
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
config USB_SN9C102
|
||||
tristate "USB SN9C10x PC Camera Controller support"
|
||||
tristate "USB SN9C1xx PC Camera Controller support"
|
||||
depends on USB && VIDEO_V4L1
|
||||
---help---
|
||||
Say Y here if you want support for cameras based on SONiX SN9C101,
|
||||
SN9C102 or SN9C103 PC Camera Controllers.
|
||||
SN9C102, SN9C103, SN9C105 and SN9C120 PC Camera Controllers.
|
||||
|
||||
See <file:Documentation/video4linux/sn9c102.txt> for more info.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
sn9c102-objs := sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o \
|
||||
sn9c102_ov7630.o sn9c102_pas106b.o sn9c102_pas202bca.o \
|
||||
sn9c102_ov7630.o sn9c102_ov7660.o sn9c102_pas106b.o \
|
||||
sn9c102_pas202bcb.o sn9c102_tas5110c1b.o \
|
||||
sn9c102_tas5130d1b.o
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/***************************************************************************
|
||||
* V4L2 driver for SN9C10x PC Camera Controllers *
|
||||
* V4L2 driver for SN9C1xx PC Camera Controllers *
|
||||
* *
|
||||
* Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
|
||||
* *
|
||||
|
@ -37,33 +37,10 @@
|
|||
#include <linux/string.h>
|
||||
#include <linux/stddef.h>
|
||||
|
||||
#include "sn9c102_config.h"
|
||||
#include "sn9c102_sensor.h"
|
||||
#include "sn9c102_devtable.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#define SN9C102_DEBUG
|
||||
#define SN9C102_DEBUG_LEVEL 2
|
||||
#define SN9C102_MAX_DEVICES 64
|
||||
#define SN9C102_PRESERVE_IMGSCALE 0
|
||||
#define SN9C102_FORCE_MUNMAP 0
|
||||
#define SN9C102_MAX_FRAMES 32
|
||||
#define SN9C102_URBS 2
|
||||
#define SN9C102_ISO_PACKETS 7
|
||||
#define SN9C102_ALTERNATE_SETTING 8
|
||||
#define SN9C102_URB_TIMEOUT msecs_to_jiffies(2 * SN9C102_ISO_PACKETS)
|
||||
#define SN9C102_CTRL_TIMEOUT 300
|
||||
#define SN9C102_FRAME_TIMEOUT 2
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
enum sn9c102_bridge {
|
||||
BRIDGE_SN9C101 = 0x01,
|
||||
BRIDGE_SN9C102 = 0x02,
|
||||
BRIDGE_SN9C103 = 0x04,
|
||||
};
|
||||
|
||||
SN9C102_ID_TABLE
|
||||
SN9C102_SENSOR_TABLE
|
||||
|
||||
enum sn9c102_frame_state {
|
||||
F_UNUSED,
|
||||
|
@ -99,13 +76,11 @@ enum sn9c102_stream_state {
|
|||
STREAM_ON,
|
||||
};
|
||||
|
||||
typedef char sn9c103_sof_header_t[18];
|
||||
typedef char sn9c102_sof_header_t[12];
|
||||
typedef char sn9c102_eof_header_t[4];
|
||||
typedef char sn9c102_sof_header_t[62];
|
||||
|
||||
struct sn9c102_sysfs_attr {
|
||||
u8 reg, i2c_reg;
|
||||
sn9c103_sof_header_t frame_header;
|
||||
sn9c102_sof_header_t frame_header;
|
||||
};
|
||||
|
||||
struct sn9c102_module_param {
|
||||
|
@ -137,8 +112,8 @@ struct sn9c102_device {
|
|||
struct v4l2_jpegcompression compression;
|
||||
|
||||
struct sn9c102_sysfs_attr sysfs;
|
||||
sn9c103_sof_header_t sof_header;
|
||||
u16 reg[63];
|
||||
sn9c102_sof_header_t sof_header;
|
||||
u16 reg[384];
|
||||
|
||||
struct sn9c102_module_param module_param;
|
||||
|
||||
|
@ -155,10 +130,7 @@ struct sn9c102_device {
|
|||
struct sn9c102_device*
|
||||
sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id)
|
||||
{
|
||||
if (usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id))
|
||||
return cam;
|
||||
|
||||
return NULL;
|
||||
return usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id) ? cam : NULL;
|
||||
}
|
||||
|
||||
|
||||
|
@ -169,6 +141,19 @@ sn9c102_attach_sensor(struct sn9c102_device* cam,
|
|||
memcpy(&cam->sensor, sensor, sizeof(struct sn9c102_sensor));
|
||||
}
|
||||
|
||||
|
||||
enum sn9c102_bridge
|
||||
sn9c102_get_bridge(struct sn9c102_device* cam)
|
||||
{
|
||||
return cam->bridge;
|
||||
}
|
||||
|
||||
|
||||
struct sn9c102_sensor* sn9c102_get_sensor(struct sn9c102_device* cam)
|
||||
{
|
||||
return &cam->sensor;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#undef DBG
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
/***************************************************************************
|
||||
* Global parameters for the V4L2 driver for SN9C1xx PC Camera Controllers *
|
||||
* *
|
||||
* Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the Free Software *
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef _SN9C102_CONFIG_H_
|
||||
#define _SN9C102_CONFIG_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/jiffies.h>
|
||||
|
||||
#define SN9C102_DEBUG
|
||||
#define SN9C102_DEBUG_LEVEL 2
|
||||
#define SN9C102_MAX_DEVICES 64
|
||||
#define SN9C102_PRESERVE_IMGSCALE 0
|
||||
#define SN9C102_FORCE_MUNMAP 0
|
||||
#define SN9C102_MAX_FRAMES 32
|
||||
#define SN9C102_URBS 2
|
||||
#define SN9C102_ISO_PACKETS 7
|
||||
#define SN9C102_ALTERNATE_SETTING 8
|
||||
#define SN9C102_URB_TIMEOUT msecs_to_jiffies(2 * SN9C102_ISO_PACKETS)
|
||||
#define SN9C102_CTRL_TIMEOUT 300
|
||||
#define SN9C102_FRAME_TIMEOUT 0
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static const u8 SN9C102_Y_QTABLE0[64] = {
|
||||
8, 5, 5, 8, 12, 20, 25, 30,
|
||||
6, 6, 7, 9, 13, 29, 30, 27,
|
||||
7, 6, 8, 12, 20, 28, 34, 28,
|
||||
7, 8, 11, 14, 25, 43, 40, 31,
|
||||
9, 11, 18, 28, 34, 54, 51, 38,
|
||||
12, 17, 27, 32, 40, 52, 56, 46,
|
||||
24, 32, 39, 43, 51, 60, 60, 50,
|
||||
36, 46, 47, 49, 56, 50, 51, 49
|
||||
};
|
||||
|
||||
static const u8 SN9C102_UV_QTABLE0[64] = {
|
||||
8, 9, 12, 23, 49, 49, 49, 49,
|
||||
9, 10, 13, 33, 49, 49, 49, 49,
|
||||
12, 13, 28, 49, 49, 49, 49, 49,
|
||||
23, 33, 49, 49, 49, 49, 49, 49,
|
||||
49, 49, 49, 49, 49, 49, 49, 49,
|
||||
49, 49, 49, 49, 49, 49, 49, 49,
|
||||
49, 49, 49, 49, 49, 49, 49, 49,
|
||||
49, 49, 49, 49, 49, 49, 49, 49
|
||||
};
|
||||
|
||||
static const u8 SN9C102_Y_QTABLE1[64] = {
|
||||
16, 11, 10, 16, 24, 40, 51, 61,
|
||||
12, 12, 14, 19, 26, 58, 60, 55,
|
||||
14, 13, 16, 24, 40, 57, 69, 56,
|
||||
14, 17, 22, 29, 51, 87, 80, 62,
|
||||
18, 22, 37, 56, 68, 109, 103, 77,
|
||||
24, 35, 55, 64, 81, 104, 113, 92,
|
||||
49, 64, 78, 87, 103, 121, 120, 101,
|
||||
72, 92, 95, 98, 112, 100, 103, 99
|
||||
};
|
||||
|
||||
static const u8 SN9C102_UV_QTABLE1[64] = {
|
||||
17, 18, 24, 47, 99, 99, 99, 99,
|
||||
18, 21, 26, 66, 99, 99, 99, 99,
|
||||
24, 26, 56, 99, 99, 99, 99, 99,
|
||||
47, 66, 99, 99, 99, 99, 99, 99,
|
||||
99, 99, 99, 99, 99, 99, 99, 99,
|
||||
99, 99, 99, 99, 99, 99, 99, 99,
|
||||
99, 99, 99, 99, 99, 99, 99, 99,
|
||||
99, 99, 99, 99, 99, 99, 99, 99
|
||||
};
|
||||
|
||||
#endif /* _SN9C102_CONFIG_H_ */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,142 @@
|
|||
/***************************************************************************
|
||||
* Table of device identifiers of the SN9C1xx PC Camera Controllers *
|
||||
* *
|
||||
* Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the Free Software *
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef _SN9C102_DEVTABLE_H_
|
||||
#define _SN9C102_DEVTABLE_H_
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
struct sn9c102_device;
|
||||
|
||||
/*
|
||||
Each SN9C1xx camera has proper PID/VID identifiers.
|
||||
SN9C103, SN9C105, SN9C120 support multiple interfaces, but we only have to
|
||||
handle the video class interface.
|
||||
*/
|
||||
#define SN9C102_USB_DEVICE(vend, prod, bridge) \
|
||||
.match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
|
||||
USB_DEVICE_ID_MATCH_INT_CLASS, \
|
||||
.idVendor = (vend), \
|
||||
.idProduct = (prod), \
|
||||
.bInterfaceClass = 0xff, \
|
||||
.driver_info = (bridge)
|
||||
|
||||
static const struct usb_device_id sn9c102_id_table[] = {
|
||||
/* SN9C101 and SN9C102 */
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x6001, BRIDGE_SN9C102), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x6005, BRIDGE_SN9C102), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x6007, BRIDGE_SN9C102), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x6009, BRIDGE_SN9C102), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x6011, BRIDGE_SN9C102), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x600d, BRIDGE_SN9C102), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x6019, BRIDGE_SN9C102), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x6024, BRIDGE_SN9C102), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x6025, BRIDGE_SN9C102), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x6028, BRIDGE_SN9C102), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x6029, BRIDGE_SN9C102), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x602a, BRIDGE_SN9C102), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x602b, BRIDGE_SN9C102), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x602c, BRIDGE_SN9C102), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x602d, BRIDGE_SN9C102), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x602e, BRIDGE_SN9C102), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x6030, BRIDGE_SN9C102), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x603f, BRIDGE_SN9C102), },
|
||||
/* SN9C103 */
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x6080, BRIDGE_SN9C103), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x6082, BRIDGE_SN9C103), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x6083, BRIDGE_SN9C103), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x6088, BRIDGE_SN9C103), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x608a, BRIDGE_SN9C103), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x608b, BRIDGE_SN9C103), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x608c, BRIDGE_SN9C103), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x608e, BRIDGE_SN9C103), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x608f, BRIDGE_SN9C103), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60a0, BRIDGE_SN9C103), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60a2, BRIDGE_SN9C103), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60a3, BRIDGE_SN9C103), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60a8, BRIDGE_SN9C103), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60aa, BRIDGE_SN9C103), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60ab, BRIDGE_SN9C103), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60ac, BRIDGE_SN9C103), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60ae, BRIDGE_SN9C103), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60af, BRIDGE_SN9C103), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60b0, BRIDGE_SN9C103), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60b2, BRIDGE_SN9C103), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60b3, BRIDGE_SN9C103), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60b8, BRIDGE_SN9C103), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60ba, BRIDGE_SN9C103), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60bb, BRIDGE_SN9C103), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60bc, BRIDGE_SN9C103), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60be, BRIDGE_SN9C103), },
|
||||
/* SN9C105 */
|
||||
{ SN9C102_USB_DEVICE(0x0471, 0x0327, BRIDGE_SN9C105), },
|
||||
{ SN9C102_USB_DEVICE(0x0471, 0x0328, BRIDGE_SN9C105), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60c0, BRIDGE_SN9C105), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60c8, BRIDGE_SN9C105), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60cc, BRIDGE_SN9C105), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60ea, BRIDGE_SN9C105), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60ec, BRIDGE_SN9C105), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60fa, BRIDGE_SN9C105), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60fb, BRIDGE_SN9C105), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60fc, BRIDGE_SN9C105), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60fe, BRIDGE_SN9C105), },
|
||||
/* SN9C120 */
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x6130, BRIDGE_SN9C120), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x613a, BRIDGE_SN9C120), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x613c, BRIDGE_SN9C120), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x613e, BRIDGE_SN9C120), },
|
||||
{ }
|
||||
};
|
||||
|
||||
/*
|
||||
Probing functions: on success, you must attach the sensor to the camera
|
||||
by calling sn9c102_attach_sensor().
|
||||
To enable the I2C communication, you might need to perform a really basic
|
||||
initialization of the SN9C1XX chip.
|
||||
Functions must return 0 on success, the appropriate error otherwise.
|
||||
*/
|
||||
extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam);
|
||||
extern int sn9c102_probe_mi0343(struct sn9c102_device* cam);
|
||||
extern int sn9c102_probe_ov7630(struct sn9c102_device* cam);
|
||||
extern int sn9c102_probe_ov7660(struct sn9c102_device* cam);
|
||||
extern int sn9c102_probe_pas106b(struct sn9c102_device* cam);
|
||||
extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam);
|
||||
extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam);
|
||||
extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam);
|
||||
|
||||
/*
|
||||
Add the above entries to this table. Be sure to add the entry in the right
|
||||
place, since, on failure, the next probing routine is called according to
|
||||
the order of the list below, from top to bottom.
|
||||
*/
|
||||
static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = {
|
||||
&sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */
|
||||
&sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */
|
||||
&sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */
|
||||
&sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */
|
||||
&sn9c102_probe_ov7630, /* strong detection based on SENSOR ids */
|
||||
&sn9c102_probe_ov7660, /* strong detection based on SENSOR ids */
|
||||
&sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */
|
||||
&sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */
|
||||
NULL,
|
||||
};
|
||||
|
||||
#endif /* _SN9C102_DEVTABLE_H_ */
|
|
@ -1,8 +1,8 @@
|
|||
/***************************************************************************
|
||||
* Plug-in for HV7131D image sensor connected to the SN9C10x PC Camera *
|
||||
* Plug-in for HV7131D image sensor connected to the SN9C1xx PC Camera *
|
||||
* Controllers *
|
||||
* *
|
||||
* Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
|
||||
* Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
|
@ -124,7 +124,7 @@ static int hv7131d_set_ctrl(struct sn9c102_device* cam,
|
|||
static int hv7131d_set_crop(struct sn9c102_device* cam,
|
||||
const struct v4l2_rect* rect)
|
||||
{
|
||||
struct sn9c102_sensor* s = &hv7131d;
|
||||
struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
|
||||
int err = 0;
|
||||
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 2,
|
||||
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2;
|
||||
|
@ -153,6 +153,7 @@ static int hv7131d_set_pix_format(struct sn9c102_device* cam,
|
|||
static struct sn9c102_sensor hv7131d = {
|
||||
.name = "HV7131D",
|
||||
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
|
||||
.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
|
||||
.sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
|
||||
.frequency = SN9C102_I2C_100KHZ,
|
||||
.interface = SN9C102_I2C_2WIRES,
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
/***************************************************************************
|
||||
* Plug-in for MI-0343 image sensor connected to the SN9C10x PC Camera *
|
||||
* Plug-in for MI-0343 image sensor connected to the SN9C1xx PC Camera *
|
||||
* Controllers *
|
||||
* *
|
||||
* Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
|
||||
* Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
|
@ -201,7 +201,7 @@ static int mi0343_set_ctrl(struct sn9c102_device* cam,
|
|||
static int mi0343_set_crop(struct sn9c102_device* cam,
|
||||
const struct v4l2_rect* rect)
|
||||
{
|
||||
struct sn9c102_sensor* s = &mi0343;
|
||||
struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
|
||||
int err = 0;
|
||||
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 0,
|
||||
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2;
|
||||
|
@ -237,6 +237,7 @@ static int mi0343_set_pix_format(struct sn9c102_device* cam,
|
|||
static struct sn9c102_sensor mi0343 = {
|
||||
.name = "MI-0343",
|
||||
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
|
||||
.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
|
||||
.frequency = SN9C102_I2C_100KHZ,
|
||||
.interface = SN9C102_I2C_2WIRES,
|
||||
.i2c_slave_id = 0x5d,
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
/***************************************************************************
|
||||
* Plug-in for OV7630 image sensor connected to the SN9C10x PC Camera *
|
||||
* Plug-in for OV7630 image sensor connected to the SN9C1xx PC Camera *
|
||||
* Controllers *
|
||||
* *
|
||||
* Copyright (C) 2005-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
|
||||
* Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
|
@ -29,13 +29,17 @@ static int ov7630_init(struct sn9c102_device* cam)
|
|||
{
|
||||
int err = 0;
|
||||
|
||||
switch (sn9c102_get_bridge(cam)) {
|
||||
case BRIDGE_SN9C101:
|
||||
case BRIDGE_SN9C102:
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x14);
|
||||
err += sn9c102_write_reg(cam, 0x60, 0x17);
|
||||
err += sn9c102_write_reg(cam, 0x0f, 0x18);
|
||||
err += sn9c102_write_reg(cam, 0x50, 0x19);
|
||||
|
||||
err += sn9c102_i2c_write(cam, 0x12, 0x80);
|
||||
err += sn9c102_i2c_write(cam, 0x11, 0x01);
|
||||
err += sn9c102_i2c_write(cam, 0x12, 0x8d);
|
||||
err += sn9c102_i2c_write(cam, 0x12, 0x0d);
|
||||
err += sn9c102_i2c_write(cam, 0x11, 0x00);
|
||||
err += sn9c102_i2c_write(cam, 0x15, 0x34);
|
||||
err += sn9c102_i2c_write(cam, 0x16, 0x03);
|
||||
err += sn9c102_i2c_write(cam, 0x17, 0x1c);
|
||||
|
@ -43,14 +47,72 @@ static int ov7630_init(struct sn9c102_device* cam)
|
|||
err += sn9c102_i2c_write(cam, 0x19, 0x06);
|
||||
err += sn9c102_i2c_write(cam, 0x1a, 0xf6);
|
||||
err += sn9c102_i2c_write(cam, 0x1b, 0x04);
|
||||
err += sn9c102_i2c_write(cam, 0x20, 0xf6);
|
||||
err += sn9c102_i2c_write(cam, 0x20, 0x44);
|
||||
err += sn9c102_i2c_write(cam, 0x23, 0xee);
|
||||
err += sn9c102_i2c_write(cam, 0x26, 0xa0);
|
||||
err += sn9c102_i2c_write(cam, 0x27, 0x9a);
|
||||
err += sn9c102_i2c_write(cam, 0x28, 0x20);
|
||||
err += sn9c102_i2c_write(cam, 0x29, 0x30);
|
||||
err += sn9c102_i2c_write(cam, 0x2f, 0x3d);
|
||||
err += sn9c102_i2c_write(cam, 0x30, 0x24);
|
||||
err += sn9c102_i2c_write(cam, 0x32, 0x86);
|
||||
err += sn9c102_i2c_write(cam, 0x60, 0xa9);
|
||||
err += sn9c102_i2c_write(cam, 0x61, 0x42);
|
||||
err += sn9c102_i2c_write(cam, 0x65, 0x00);
|
||||
err += sn9c102_i2c_write(cam, 0x69, 0x38);
|
||||
err += sn9c102_i2c_write(cam, 0x6f, 0x88);
|
||||
err += sn9c102_i2c_write(cam, 0x70, 0x0b);
|
||||
err += sn9c102_i2c_write(cam, 0x71, 0x00);
|
||||
err += sn9c102_i2c_write(cam, 0x74, 0x21);
|
||||
err += sn9c102_i2c_write(cam, 0x7d, 0xf7);
|
||||
break;
|
||||
case BRIDGE_SN9C103:
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x02);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x03);
|
||||
err += sn9c102_write_reg(cam, 0x1a, 0x04);
|
||||
err += sn9c102_write_reg(cam, 0x20, 0x05);
|
||||
err += sn9c102_write_reg(cam, 0x20, 0x06);
|
||||
err += sn9c102_write_reg(cam, 0x20, 0x07);
|
||||
err += sn9c102_write_reg(cam, 0x03, 0x10);
|
||||
err += sn9c102_write_reg(cam, 0x0a, 0x14);
|
||||
err += sn9c102_write_reg(cam, 0x60, 0x17);
|
||||
err += sn9c102_write_reg(cam, 0x0f, 0x18);
|
||||
err += sn9c102_write_reg(cam, 0x50, 0x19);
|
||||
err += sn9c102_write_reg(cam, 0x1d, 0x1a);
|
||||
err += sn9c102_write_reg(cam, 0x10, 0x1b);
|
||||
err += sn9c102_write_reg(cam, 0x02, 0x1c);
|
||||
err += sn9c102_write_reg(cam, 0x03, 0x1d);
|
||||
err += sn9c102_write_reg(cam, 0x0f, 0x1e);
|
||||
err += sn9c102_write_reg(cam, 0x0c, 0x1f);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x20);
|
||||
err += sn9c102_write_reg(cam, 0x10, 0x21);
|
||||
err += sn9c102_write_reg(cam, 0x20, 0x22);
|
||||
err += sn9c102_write_reg(cam, 0x30, 0x23);
|
||||
err += sn9c102_write_reg(cam, 0x40, 0x24);
|
||||
err += sn9c102_write_reg(cam, 0x50, 0x25);
|
||||
err += sn9c102_write_reg(cam, 0x60, 0x26);
|
||||
err += sn9c102_write_reg(cam, 0x70, 0x27);
|
||||
err += sn9c102_write_reg(cam, 0x80, 0x28);
|
||||
err += sn9c102_write_reg(cam, 0x90, 0x29);
|
||||
err += sn9c102_write_reg(cam, 0xa0, 0x2a);
|
||||
err += sn9c102_write_reg(cam, 0xb0, 0x2b);
|
||||
err += sn9c102_write_reg(cam, 0xc0, 0x2c);
|
||||
err += sn9c102_write_reg(cam, 0xd0, 0x2d);
|
||||
err += sn9c102_write_reg(cam, 0xe0, 0x2e);
|
||||
err += sn9c102_write_reg(cam, 0xf0, 0x2f);
|
||||
err += sn9c102_write_reg(cam, 0xff, 0x30);
|
||||
|
||||
err += sn9c102_i2c_write(cam, 0x12, 0x8d);
|
||||
err += sn9c102_i2c_write(cam, 0x12, 0x0d);
|
||||
err += sn9c102_i2c_write(cam, 0x15, 0x34);
|
||||
err += sn9c102_i2c_write(cam, 0x11, 0x01);
|
||||
err += sn9c102_i2c_write(cam, 0x1b, 0x04);
|
||||
err += sn9c102_i2c_write(cam, 0x20, 0x44);
|
||||
err += sn9c102_i2c_write(cam, 0x23, 0xee);
|
||||
err += sn9c102_i2c_write(cam, 0x26, 0xa0);
|
||||
err += sn9c102_i2c_write(cam, 0x27, 0x9a);
|
||||
err += sn9c102_i2c_write(cam, 0x28, 0xa0);
|
||||
err += sn9c102_i2c_write(cam, 0x28, 0x20);
|
||||
err += sn9c102_i2c_write(cam, 0x29, 0x30);
|
||||
err += sn9c102_i2c_write(cam, 0x2a, 0xa0);
|
||||
err += sn9c102_i2c_write(cam, 0x2b, 0x1f);
|
||||
err += sn9c102_i2c_write(cam, 0x2f, 0x3d);
|
||||
err += sn9c102_i2c_write(cam, 0x30, 0x24);
|
||||
err += sn9c102_i2c_write(cam, 0x32, 0x86);
|
||||
|
@ -63,11 +125,77 @@ static int ov7630_init(struct sn9c102_device* cam)
|
|||
err += sn9c102_i2c_write(cam, 0x71, 0x00);
|
||||
err += sn9c102_i2c_write(cam, 0x74, 0x21);
|
||||
err += sn9c102_i2c_write(cam, 0x7d, 0xf7);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static int ov7630_get_ctrl(struct sn9c102_device* cam,
|
||||
struct v4l2_control* ctrl)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_EXPOSURE:
|
||||
if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0)
|
||||
return -EIO;
|
||||
break;
|
||||
case V4L2_CID_RED_BALANCE:
|
||||
ctrl->value = sn9c102_pread_reg(cam, 0x07);
|
||||
break;
|
||||
case V4L2_CID_BLUE_BALANCE:
|
||||
ctrl->value = sn9c102_pread_reg(cam, 0x06);
|
||||
break;
|
||||
case SN9C102_V4L2_CID_GREEN_BALANCE:
|
||||
ctrl->value = sn9c102_pread_reg(cam, 0x05);
|
||||
break;
|
||||
case V4L2_CID_GAIN:
|
||||
if ((ctrl->value = sn9c102_i2c_read(cam, 0x00)) < 0)
|
||||
return -EIO;
|
||||
ctrl->value &= 0x3f;
|
||||
break;
|
||||
case V4L2_CID_DO_WHITE_BALANCE:
|
||||
if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0)
|
||||
return -EIO;
|
||||
ctrl->value &= 0x3f;
|
||||
break;
|
||||
case V4L2_CID_WHITENESS:
|
||||
if ((ctrl->value = sn9c102_i2c_read(cam, 0x0d)) < 0)
|
||||
return -EIO;
|
||||
ctrl->value &= 0x3f;
|
||||
break;
|
||||
case V4L2_CID_AUTOGAIN:
|
||||
if ((ctrl->value = sn9c102_i2c_read(cam, 0x13)) < 0)
|
||||
return -EIO;
|
||||
ctrl->value &= 0x01;
|
||||
break;
|
||||
case V4L2_CID_VFLIP:
|
||||
if ((ctrl->value = sn9c102_i2c_read(cam, 0x75)) < 0)
|
||||
return -EIO;
|
||||
ctrl->value = (ctrl->value & 0x80) ? 1 : 0;
|
||||
break;
|
||||
case SN9C102_V4L2_CID_GAMMA:
|
||||
if ((ctrl->value = sn9c102_i2c_read(cam, 0x14)) < 0)
|
||||
return -EIO;
|
||||
ctrl->value = (ctrl->value & 0x02) ? 1 : 0;
|
||||
break;
|
||||
case SN9C102_V4L2_CID_BAND_FILTER:
|
||||
if ((ctrl->value = sn9c102_i2c_read(cam, 0x2d)) < 0)
|
||||
return -EIO;
|
||||
ctrl->value = (ctrl->value & 0x02) ? 1 : 0;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return err ? -EIO : 0;
|
||||
}
|
||||
|
||||
|
||||
static int ov7630_set_ctrl(struct sn9c102_device* cam,
|
||||
const struct v4l2_control* ctrl)
|
||||
{
|
||||
|
@ -75,57 +203,35 @@ static int ov7630_set_ctrl(struct sn9c102_device* cam,
|
|||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_EXPOSURE:
|
||||
err += sn9c102_i2c_write(cam, 0x10, ctrl->value >> 2);
|
||||
err += sn9c102_i2c_write(cam, 0x76, ctrl->value & 0x03);
|
||||
err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
|
||||
break;
|
||||
case V4L2_CID_RED_BALANCE:
|
||||
err += sn9c102_i2c_write(cam, 0x02, ctrl->value);
|
||||
err += sn9c102_write_reg(cam, ctrl->value, 0x07);
|
||||
break;
|
||||
case V4L2_CID_BLUE_BALANCE:
|
||||
err += sn9c102_i2c_write(cam, 0x01, ctrl->value);
|
||||
err += sn9c102_write_reg(cam, ctrl->value, 0x06);
|
||||
break;
|
||||
case SN9C102_V4L2_CID_GREEN_BALANCE:
|
||||
err += sn9c102_write_reg(cam, ctrl->value, 0x05);
|
||||
break;
|
||||
case V4L2_CID_GAIN:
|
||||
err += sn9c102_i2c_write(cam, 0x00, ctrl->value);
|
||||
break;
|
||||
case V4L2_CID_CONTRAST:
|
||||
err += ctrl->value ? sn9c102_i2c_write(cam, 0x05,
|
||||
(ctrl->value-1) | 0x20)
|
||||
: sn9c102_i2c_write(cam, 0x05, 0x00);
|
||||
break;
|
||||
case V4L2_CID_BRIGHTNESS:
|
||||
err += sn9c102_i2c_write(cam, 0x06, ctrl->value);
|
||||
break;
|
||||
case V4L2_CID_SATURATION:
|
||||
err += sn9c102_i2c_write(cam, 0x03, ctrl->value << 4);
|
||||
break;
|
||||
case V4L2_CID_HUE:
|
||||
err += ctrl->value ? sn9c102_i2c_write(cam, 0x04,
|
||||
(ctrl->value-1) | 0x20)
|
||||
: sn9c102_i2c_write(cam, 0x04, 0x00);
|
||||
break;
|
||||
case V4L2_CID_DO_WHITE_BALANCE:
|
||||
err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
|
||||
break;
|
||||
case V4L2_CID_WHITENESS:
|
||||
err += sn9c102_i2c_write(cam, 0x0d, ctrl->value);
|
||||
break;
|
||||
case V4L2_CID_AUTO_WHITE_BALANCE:
|
||||
err += sn9c102_i2c_write(cam, 0x12, (ctrl->value << 2) | 0x78);
|
||||
break;
|
||||
case V4L2_CID_AUTOGAIN:
|
||||
err += sn9c102_i2c_write(cam, 0x13, ctrl->value);
|
||||
err += sn9c102_i2c_write(cam, 0x13, ctrl->value |
|
||||
(ctrl->value << 1));
|
||||
break;
|
||||
case V4L2_CID_VFLIP:
|
||||
err += sn9c102_i2c_write(cam, 0x75, 0x0e | (ctrl->value << 7));
|
||||
break;
|
||||
case V4L2_CID_BLACK_LEVEL:
|
||||
err += sn9c102_i2c_write(cam, 0x25, ctrl->value);
|
||||
break;
|
||||
case SN9C102_V4L2_CID_BRIGHT_LEVEL:
|
||||
err += sn9c102_i2c_write(cam, 0x24, ctrl->value);
|
||||
break;
|
||||
case SN9C102_V4L2_CID_GAMMA:
|
||||
err += sn9c102_i2c_write(cam, 0x14, (ctrl->value << 2) | 0x80);
|
||||
err += sn9c102_i2c_write(cam, 0x14, ctrl->value << 2);
|
||||
break;
|
||||
case SN9C102_V4L2_CID_BAND_FILTER:
|
||||
err += sn9c102_i2c_write(cam, 0x2d, ctrl->value << 2);
|
||||
|
@ -141,10 +247,12 @@ static int ov7630_set_ctrl(struct sn9c102_device* cam,
|
|||
static int ov7630_set_crop(struct sn9c102_device* cam,
|
||||
const struct v4l2_rect* rect)
|
||||
{
|
||||
struct sn9c102_sensor* s = &ov7630;
|
||||
struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
|
||||
int err = 0;
|
||||
u8 v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
|
||||
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1,
|
||||
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
|
||||
|
||||
err += sn9c102_write_reg(cam, h_start, 0x12);
|
||||
err += sn9c102_write_reg(cam, v_start, 0x13);
|
||||
|
||||
return err;
|
||||
|
@ -168,7 +276,8 @@ static int ov7630_set_pix_format(struct sn9c102_device* cam,
|
|||
static struct sn9c102_sensor ov7630 = {
|
||||
.name = "OV7630",
|
||||
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
|
||||
.sysfs_ops = SN9C102_I2C_WRITE,
|
||||
.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
|
||||
.sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
|
||||
.frequency = SN9C102_I2C_100KHZ,
|
||||
.interface = SN9C102_I2C_2WIRES,
|
||||
.i2c_slave_id = 0x21,
|
||||
|
@ -184,84 +293,14 @@ static struct sn9c102_sensor ov7630 = {
|
|||
.default_value = 0x14,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_HUE,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "hue",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0x1f+1,
|
||||
.step = 0x01,
|
||||
.default_value = 0x00,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_SATURATION,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "saturation",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0x0f,
|
||||
.step = 0x01,
|
||||
.default_value = 0x08,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_CONTRAST,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "contrast",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0x1f+1,
|
||||
.step = 0x01,
|
||||
.default_value = 0x00,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_EXPOSURE,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "exposure",
|
||||
.minimum = 0x000,
|
||||
.maximum = 0x3ff,
|
||||
.step = 0x001,
|
||||
.default_value = 0x83<<2,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_RED_BALANCE,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "red balance",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0xff,
|
||||
.step = 0x01,
|
||||
.default_value = 0x3a,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_BLUE_BALANCE,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "blue balance",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0xff,
|
||||
.step = 0x01,
|
||||
.default_value = 0x77,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_BRIGHTNESS,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "brightness",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0xff,
|
||||
.step = 0x01,
|
||||
.default_value = 0xa0,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_DO_WHITE_BALANCE,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "white balance background: blue",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0x3f,
|
||||
.step = 0x01,
|
||||
.default_value = 0x20,
|
||||
.default_value = 0x60,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
|
@ -275,21 +314,41 @@ static struct sn9c102_sensor ov7630 = {
|
|||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_AUTO_WHITE_BALANCE,
|
||||
.type = V4L2_CTRL_TYPE_BOOLEAN,
|
||||
.name = "auto white balance",
|
||||
.id = V4L2_CID_DO_WHITE_BALANCE,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "white balance background: blue",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0x01,
|
||||
.maximum = 0x3f,
|
||||
.step = 0x01,
|
||||
.default_value = 0x01,
|
||||
.default_value = 0x20,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_RED_BALANCE,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "red balance",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0x7f,
|
||||
.step = 0x01,
|
||||
.default_value = 0x20,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_BLUE_BALANCE,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "blue balance",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0x7f,
|
||||
.step = 0x01,
|
||||
.default_value = 0x20,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_AUTOGAIN,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "gain & exposure mode",
|
||||
.type = V4L2_CTRL_TYPE_BOOLEAN,
|
||||
.name = "auto adjust",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0x03,
|
||||
.maximum = 0x01,
|
||||
.step = 0x01,
|
||||
.default_value = 0x00,
|
||||
.flags = 0,
|
||||
|
@ -305,23 +364,13 @@ static struct sn9c102_sensor ov7630 = {
|
|||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_BLACK_LEVEL,
|
||||
.id = SN9C102_V4L2_CID_GREEN_BALANCE,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "black pixel ratio",
|
||||
.minimum = 0x01,
|
||||
.maximum = 0x9a,
|
||||
.name = "green balance",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0x7f,
|
||||
.step = 0x01,
|
||||
.default_value = 0x8a,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = SN9C102_V4L2_CID_BRIGHT_LEVEL,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "bright pixel ratio",
|
||||
.minimum = 0x01,
|
||||
.maximum = 0x9a,
|
||||
.step = 0x01,
|
||||
.default_value = 0x10,
|
||||
.default_value = 0x20,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
|
@ -345,6 +394,7 @@ static struct sn9c102_sensor ov7630 = {
|
|||
.flags = 0,
|
||||
},
|
||||
},
|
||||
.get_ctrl = &ov7630_get_ctrl,
|
||||
.set_ctrl = &ov7630_set_ctrl,
|
||||
.cropcap = {
|
||||
.bounds = {
|
||||
|
@ -364,7 +414,7 @@ static struct sn9c102_sensor ov7630 = {
|
|||
.pix_format = {
|
||||
.width = 640,
|
||||
.height = 480,
|
||||
.pixelformat = V4L2_PIX_FMT_SBGGR8,
|
||||
.pixelformat = V4L2_PIX_FMT_SN9C10X,
|
||||
.priv = 8,
|
||||
},
|
||||
.set_pix_format = &ov7630_set_pix_format
|
||||
|
@ -373,28 +423,36 @@ static struct sn9c102_sensor ov7630 = {
|
|||
|
||||
int sn9c102_probe_ov7630(struct sn9c102_device* cam)
|
||||
{
|
||||
const struct usb_device_id ov7630_id_table[] = {
|
||||
{ USB_DEVICE(0x0c45, 0x602c), },
|
||||
{ USB_DEVICE(0x0c45, 0x602d), },
|
||||
{ USB_DEVICE(0x0c45, 0x608f), },
|
||||
{ USB_DEVICE(0x0c45, 0x60b0), },
|
||||
{ }
|
||||
};
|
||||
int err = 0;
|
||||
|
||||
if (!sn9c102_match_id(cam, ov7630_id_table))
|
||||
return -ENODEV;
|
||||
int pid, ver, err = 0;
|
||||
|
||||
switch (sn9c102_get_bridge(cam)) {
|
||||
case BRIDGE_SN9C101:
|
||||
case BRIDGE_SN9C102:
|
||||
err += sn9c102_write_reg(cam, 0x01, 0x01);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x01);
|
||||
err += sn9c102_write_reg(cam, 0x28, 0x17);
|
||||
if (err)
|
||||
break;
|
||||
case BRIDGE_SN9C103: /* do _not_ change anything! */
|
||||
err += sn9c102_write_reg(cam, 0x09, 0x01);
|
||||
err += sn9c102_write_reg(cam, 0x42, 0x01);
|
||||
err += sn9c102_write_reg(cam, 0x28, 0x17);
|
||||
err += sn9c102_write_reg(cam, 0x44, 0x02);
|
||||
pid = sn9c102_i2c_try_read(cam, &ov7630, 0x0a);
|
||||
if (err || pid < 0) { /* try a different initialization */
|
||||
err = sn9c102_write_reg(cam, 0x01, 0x01);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x01);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
pid = sn9c102_i2c_try_read(cam, &ov7630, 0x0a);
|
||||
ver = sn9c102_i2c_try_read(cam, &ov7630, 0x0b);
|
||||
if (err || pid < 0 || ver < 0)
|
||||
return -EIO;
|
||||
|
||||
err += sn9c102_i2c_try_write(cam, &ov7630, 0x0b, 0);
|
||||
if (err)
|
||||
if (pid != 0x76 || ver != 0x31)
|
||||
return -ENODEV;
|
||||
|
||||
sn9c102_attach_sensor(cam, &ov7630);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -0,0 +1,592 @@
|
|||
/***************************************************************************
|
||||
* Plug-in for OV7660 image sensor connected to the SN9C1xx PC Camera *
|
||||
* Controllers *
|
||||
* *
|
||||
* Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the Free Software *
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#include "sn9c102_sensor.h"
|
||||
|
||||
|
||||
static struct sn9c102_sensor ov7660;
|
||||
|
||||
|
||||
static int ov7660_init(struct sn9c102_device* cam)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
err += sn9c102_write_reg(cam, 0x40, 0x02);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x03);
|
||||
err += sn9c102_write_reg(cam, 0x1a, 0x04);
|
||||
err += sn9c102_write_reg(cam, 0x03, 0x10);
|
||||
err += sn9c102_write_reg(cam, 0x08, 0x14);
|
||||
err += sn9c102_write_reg(cam, 0x20, 0x17);
|
||||
err += sn9c102_write_reg(cam, 0x8b, 0x18);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x19);
|
||||
err += sn9c102_write_reg(cam, 0x1d, 0x1a);
|
||||
err += sn9c102_write_reg(cam, 0x10, 0x1b);
|
||||
err += sn9c102_write_reg(cam, 0x02, 0x1c);
|
||||
err += sn9c102_write_reg(cam, 0x03, 0x1d);
|
||||
err += sn9c102_write_reg(cam, 0x0f, 0x1e);
|
||||
err += sn9c102_write_reg(cam, 0x0c, 0x1f);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x20);
|
||||
err += sn9c102_write_reg(cam, 0x29, 0x21);
|
||||
err += sn9c102_write_reg(cam, 0x40, 0x22);
|
||||
err += sn9c102_write_reg(cam, 0x54, 0x23);
|
||||
err += sn9c102_write_reg(cam, 0x66, 0x24);
|
||||
err += sn9c102_write_reg(cam, 0x76, 0x25);
|
||||
err += sn9c102_write_reg(cam, 0x85, 0x26);
|
||||
err += sn9c102_write_reg(cam, 0x94, 0x27);
|
||||
err += sn9c102_write_reg(cam, 0xa1, 0x28);
|
||||
err += sn9c102_write_reg(cam, 0xae, 0x29);
|
||||
err += sn9c102_write_reg(cam, 0xbb, 0x2a);
|
||||
err += sn9c102_write_reg(cam, 0xc7, 0x2b);
|
||||
err += sn9c102_write_reg(cam, 0xd3, 0x2c);
|
||||
err += sn9c102_write_reg(cam, 0xde, 0x2d);
|
||||
err += sn9c102_write_reg(cam, 0xea, 0x2e);
|
||||
err += sn9c102_write_reg(cam, 0xf4, 0x2f);
|
||||
err += sn9c102_write_reg(cam, 0xff, 0x30);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x3F);
|
||||
err += sn9c102_write_reg(cam, 0xC7, 0x40);
|
||||
err += sn9c102_write_reg(cam, 0x01, 0x41);
|
||||
err += sn9c102_write_reg(cam, 0x44, 0x42);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x43);
|
||||
err += sn9c102_write_reg(cam, 0x44, 0x44);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x45);
|
||||
err += sn9c102_write_reg(cam, 0x44, 0x46);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x47);
|
||||
err += sn9c102_write_reg(cam, 0xC7, 0x48);
|
||||
err += sn9c102_write_reg(cam, 0x01, 0x49);
|
||||
err += sn9c102_write_reg(cam, 0xC7, 0x4A);
|
||||
err += sn9c102_write_reg(cam, 0x01, 0x4B);
|
||||
err += sn9c102_write_reg(cam, 0xC7, 0x4C);
|
||||
err += sn9c102_write_reg(cam, 0x01, 0x4D);
|
||||
err += sn9c102_write_reg(cam, 0x44, 0x4E);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x4F);
|
||||
err += sn9c102_write_reg(cam, 0x44, 0x50);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x51);
|
||||
err += sn9c102_write_reg(cam, 0x44, 0x52);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x53);
|
||||
err += sn9c102_write_reg(cam, 0xC7, 0x54);
|
||||
err += sn9c102_write_reg(cam, 0x01, 0x55);
|
||||
err += sn9c102_write_reg(cam, 0xC7, 0x56);
|
||||
err += sn9c102_write_reg(cam, 0x01, 0x57);
|
||||
err += sn9c102_write_reg(cam, 0xC7, 0x58);
|
||||
err += sn9c102_write_reg(cam, 0x01, 0x59);
|
||||
err += sn9c102_write_reg(cam, 0x44, 0x5A);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x5B);
|
||||
err += sn9c102_write_reg(cam, 0x44, 0x5C);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x5D);
|
||||
err += sn9c102_write_reg(cam, 0x44, 0x5E);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x5F);
|
||||
err += sn9c102_write_reg(cam, 0xC7, 0x60);
|
||||
err += sn9c102_write_reg(cam, 0x01, 0x61);
|
||||
err += sn9c102_write_reg(cam, 0xC7, 0x62);
|
||||
err += sn9c102_write_reg(cam, 0x01, 0x63);
|
||||
err += sn9c102_write_reg(cam, 0xC7, 0x64);
|
||||
err += sn9c102_write_reg(cam, 0x01, 0x65);
|
||||
err += sn9c102_write_reg(cam, 0x44, 0x66);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x67);
|
||||
err += sn9c102_write_reg(cam, 0x44, 0x68);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x69);
|
||||
err += sn9c102_write_reg(cam, 0x44, 0x6A);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x6B);
|
||||
err += sn9c102_write_reg(cam, 0xC7, 0x6C);
|
||||
err += sn9c102_write_reg(cam, 0x01, 0x6D);
|
||||
err += sn9c102_write_reg(cam, 0xC7, 0x6E);
|
||||
err += sn9c102_write_reg(cam, 0x01, 0x6F);
|
||||
err += sn9c102_write_reg(cam, 0xC7, 0x70);
|
||||
err += sn9c102_write_reg(cam, 0x01, 0x71);
|
||||
err += sn9c102_write_reg(cam, 0x44, 0x72);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x73);
|
||||
err += sn9c102_write_reg(cam, 0x44, 0x74);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x75);
|
||||
err += sn9c102_write_reg(cam, 0x44, 0x76);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x77);
|
||||
err += sn9c102_write_reg(cam, 0xC7, 0x78);
|
||||
err += sn9c102_write_reg(cam, 0x01, 0x79);
|
||||
err += sn9c102_write_reg(cam, 0xC7, 0x7A);
|
||||
err += sn9c102_write_reg(cam, 0x01, 0x7B);
|
||||
err += sn9c102_write_reg(cam, 0xC7, 0x7C);
|
||||
err += sn9c102_write_reg(cam, 0x01, 0x7D);
|
||||
err += sn9c102_write_reg(cam, 0x44, 0x7E);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x7F);
|
||||
err += sn9c102_write_reg(cam, 0x14, 0x84);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x85);
|
||||
err += sn9c102_write_reg(cam, 0x27, 0x86);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x87);
|
||||
err += sn9c102_write_reg(cam, 0x07, 0x88);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x89);
|
||||
err += sn9c102_write_reg(cam, 0xEC, 0x8A);
|
||||
err += sn9c102_write_reg(cam, 0x0f, 0x8B);
|
||||
err += sn9c102_write_reg(cam, 0xD8, 0x8C);
|
||||
err += sn9c102_write_reg(cam, 0x0f, 0x8D);
|
||||
err += sn9c102_write_reg(cam, 0x3D, 0x8E);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x8F);
|
||||
err += sn9c102_write_reg(cam, 0x3D, 0x90);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x91);
|
||||
err += sn9c102_write_reg(cam, 0xCD, 0x92);
|
||||
err += sn9c102_write_reg(cam, 0x0f, 0x93);
|
||||
err += sn9c102_write_reg(cam, 0xf7, 0x94);
|
||||
err += sn9c102_write_reg(cam, 0x0f, 0x95);
|
||||
err += sn9c102_write_reg(cam, 0x0C, 0x96);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x97);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x98);
|
||||
err += sn9c102_write_reg(cam, 0x66, 0x99);
|
||||
err += sn9c102_write_reg(cam, 0x05, 0x9A);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x9B);
|
||||
err += sn9c102_write_reg(cam, 0x04, 0x9C);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x9D);
|
||||
err += sn9c102_write_reg(cam, 0x08, 0x9E);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x9F);
|
||||
err += sn9c102_write_reg(cam, 0x2D, 0xC0);
|
||||
err += sn9c102_write_reg(cam, 0x2D, 0xC1);
|
||||
err += sn9c102_write_reg(cam, 0x3A, 0xC2);
|
||||
err += sn9c102_write_reg(cam, 0x05, 0xC3);
|
||||
err += sn9c102_write_reg(cam, 0x04, 0xC4);
|
||||
err += sn9c102_write_reg(cam, 0x3F, 0xC5);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0xC6);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0xC7);
|
||||
err += sn9c102_write_reg(cam, 0x50, 0xC8);
|
||||
err += sn9c102_write_reg(cam, 0x3C, 0xC9);
|
||||
err += sn9c102_write_reg(cam, 0x28, 0xCA);
|
||||
err += sn9c102_write_reg(cam, 0xD8, 0xCB);
|
||||
err += sn9c102_write_reg(cam, 0x14, 0xCC);
|
||||
err += sn9c102_write_reg(cam, 0xEC, 0xCD);
|
||||
err += sn9c102_write_reg(cam, 0x32, 0xCE);
|
||||
err += sn9c102_write_reg(cam, 0xDD, 0xCF);
|
||||
err += sn9c102_write_reg(cam, 0x32, 0xD0);
|
||||
err += sn9c102_write_reg(cam, 0xDD, 0xD1);
|
||||
err += sn9c102_write_reg(cam, 0x6A, 0xD2);
|
||||
err += sn9c102_write_reg(cam, 0x50, 0xD3);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0xD4);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0xD5);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0xD6);
|
||||
|
||||
err += sn9c102_i2c_write(cam, 0x12, 0x80);
|
||||
err += sn9c102_i2c_write(cam, 0x11, 0x09);
|
||||
err += sn9c102_i2c_write(cam, 0x00, 0x0A);
|
||||
err += sn9c102_i2c_write(cam, 0x01, 0x78);
|
||||
err += sn9c102_i2c_write(cam, 0x02, 0x90);
|
||||
err += sn9c102_i2c_write(cam, 0x03, 0x00);
|
||||
err += sn9c102_i2c_write(cam, 0x04, 0x00);
|
||||
err += sn9c102_i2c_write(cam, 0x05, 0x08);
|
||||
err += sn9c102_i2c_write(cam, 0x06, 0x0B);
|
||||
err += sn9c102_i2c_write(cam, 0x07, 0x00);
|
||||
err += sn9c102_i2c_write(cam, 0x08, 0x1C);
|
||||
err += sn9c102_i2c_write(cam, 0x09, 0x01);
|
||||
err += sn9c102_i2c_write(cam, 0x0A, 0x76);
|
||||
err += sn9c102_i2c_write(cam, 0x0B, 0x60);
|
||||
err += sn9c102_i2c_write(cam, 0x0C, 0x00);
|
||||
err += sn9c102_i2c_write(cam, 0x0D, 0x08);
|
||||
err += sn9c102_i2c_write(cam, 0x0E, 0x04);
|
||||
err += sn9c102_i2c_write(cam, 0x0F, 0x6F);
|
||||
err += sn9c102_i2c_write(cam, 0x10, 0x20);
|
||||
err += sn9c102_i2c_write(cam, 0x11, 0x03);
|
||||
err += sn9c102_i2c_write(cam, 0x12, 0x05);
|
||||
err += sn9c102_i2c_write(cam, 0x13, 0xF8);
|
||||
err += sn9c102_i2c_write(cam, 0x14, 0x2C);
|
||||
err += sn9c102_i2c_write(cam, 0x15, 0x00);
|
||||
err += sn9c102_i2c_write(cam, 0x16, 0x02);
|
||||
err += sn9c102_i2c_write(cam, 0x17, 0x10);
|
||||
err += sn9c102_i2c_write(cam, 0x18, 0x60);
|
||||
err += sn9c102_i2c_write(cam, 0x19, 0x02);
|
||||
err += sn9c102_i2c_write(cam, 0x1A, 0x7B);
|
||||
err += sn9c102_i2c_write(cam, 0x1B, 0x02);
|
||||
err += sn9c102_i2c_write(cam, 0x1C, 0x7F);
|
||||
err += sn9c102_i2c_write(cam, 0x1D, 0xA2);
|
||||
err += sn9c102_i2c_write(cam, 0x1E, 0x01);
|
||||
err += sn9c102_i2c_write(cam, 0x1F, 0x0E);
|
||||
err += sn9c102_i2c_write(cam, 0x20, 0x05);
|
||||
err += sn9c102_i2c_write(cam, 0x21, 0x05);
|
||||
err += sn9c102_i2c_write(cam, 0x22, 0x05);
|
||||
err += sn9c102_i2c_write(cam, 0x23, 0x05);
|
||||
err += sn9c102_i2c_write(cam, 0x24, 0x68);
|
||||
err += sn9c102_i2c_write(cam, 0x25, 0x58);
|
||||
err += sn9c102_i2c_write(cam, 0x26, 0xD4);
|
||||
err += sn9c102_i2c_write(cam, 0x27, 0x80);
|
||||
err += sn9c102_i2c_write(cam, 0x28, 0x80);
|
||||
err += sn9c102_i2c_write(cam, 0x29, 0x30);
|
||||
err += sn9c102_i2c_write(cam, 0x2A, 0x00);
|
||||
err += sn9c102_i2c_write(cam, 0x2B, 0x00);
|
||||
err += sn9c102_i2c_write(cam, 0x2C, 0x80);
|
||||
err += sn9c102_i2c_write(cam, 0x2D, 0x00);
|
||||
err += sn9c102_i2c_write(cam, 0x2E, 0x00);
|
||||
err += sn9c102_i2c_write(cam, 0x2F, 0x0E);
|
||||
err += sn9c102_i2c_write(cam, 0x30, 0x08);
|
||||
err += sn9c102_i2c_write(cam, 0x31, 0x30);
|
||||
err += sn9c102_i2c_write(cam, 0x32, 0xB4);
|
||||
err += sn9c102_i2c_write(cam, 0x33, 0x00);
|
||||
err += sn9c102_i2c_write(cam, 0x34, 0x07);
|
||||
err += sn9c102_i2c_write(cam, 0x35, 0x84);
|
||||
err += sn9c102_i2c_write(cam, 0x36, 0x00);
|
||||
err += sn9c102_i2c_write(cam, 0x37, 0x0C);
|
||||
err += sn9c102_i2c_write(cam, 0x38, 0x02);
|
||||
err += sn9c102_i2c_write(cam, 0x39, 0x43);
|
||||
err += sn9c102_i2c_write(cam, 0x3A, 0x00);
|
||||
err += sn9c102_i2c_write(cam, 0x3B, 0x02);
|
||||
err += sn9c102_i2c_write(cam, 0x3C, 0x6C);
|
||||
err += sn9c102_i2c_write(cam, 0x3D, 0x99);
|
||||
err += sn9c102_i2c_write(cam, 0x3E, 0x0E);
|
||||
err += sn9c102_i2c_write(cam, 0x3F, 0x41);
|
||||
err += sn9c102_i2c_write(cam, 0x40, 0xC1);
|
||||
err += sn9c102_i2c_write(cam, 0x41, 0x22);
|
||||
err += sn9c102_i2c_write(cam, 0x42, 0x08);
|
||||
err += sn9c102_i2c_write(cam, 0x43, 0xF0);
|
||||
err += sn9c102_i2c_write(cam, 0x44, 0x10);
|
||||
err += sn9c102_i2c_write(cam, 0x45, 0x78);
|
||||
err += sn9c102_i2c_write(cam, 0x46, 0xA8);
|
||||
err += sn9c102_i2c_write(cam, 0x47, 0x60);
|
||||
err += sn9c102_i2c_write(cam, 0x48, 0x80);
|
||||
err += sn9c102_i2c_write(cam, 0x49, 0x00);
|
||||
err += sn9c102_i2c_write(cam, 0x4A, 0x00);
|
||||
err += sn9c102_i2c_write(cam, 0x4B, 0x00);
|
||||
err += sn9c102_i2c_write(cam, 0x4C, 0x00);
|
||||
err += sn9c102_i2c_write(cam, 0x4D, 0x00);
|
||||
err += sn9c102_i2c_write(cam, 0x4E, 0x00);
|
||||
err += sn9c102_i2c_write(cam, 0x4F, 0x46);
|
||||
err += sn9c102_i2c_write(cam, 0x50, 0x36);
|
||||
err += sn9c102_i2c_write(cam, 0x51, 0x0F);
|
||||
err += sn9c102_i2c_write(cam, 0x52, 0x17);
|
||||
err += sn9c102_i2c_write(cam, 0x53, 0x7F);
|
||||
err += sn9c102_i2c_write(cam, 0x54, 0x96);
|
||||
err += sn9c102_i2c_write(cam, 0x55, 0x40);
|
||||
err += sn9c102_i2c_write(cam, 0x56, 0x40);
|
||||
err += sn9c102_i2c_write(cam, 0x57, 0x40);
|
||||
err += sn9c102_i2c_write(cam, 0x58, 0x0F);
|
||||
err += sn9c102_i2c_write(cam, 0x59, 0xBA);
|
||||
err += sn9c102_i2c_write(cam, 0x5A, 0x9A);
|
||||
err += sn9c102_i2c_write(cam, 0x5B, 0x22);
|
||||
err += sn9c102_i2c_write(cam, 0x5C, 0xB9);
|
||||
err += sn9c102_i2c_write(cam, 0x5D, 0x9B);
|
||||
err += sn9c102_i2c_write(cam, 0x5E, 0x10);
|
||||
err += sn9c102_i2c_write(cam, 0x5F, 0xF0);
|
||||
err += sn9c102_i2c_write(cam, 0x60, 0x05);
|
||||
err += sn9c102_i2c_write(cam, 0x61, 0x60);
|
||||
err += sn9c102_i2c_write(cam, 0x62, 0x00);
|
||||
err += sn9c102_i2c_write(cam, 0x63, 0x00);
|
||||
err += sn9c102_i2c_write(cam, 0x64, 0x50);
|
||||
err += sn9c102_i2c_write(cam, 0x65, 0x30);
|
||||
err += sn9c102_i2c_write(cam, 0x66, 0x00);
|
||||
err += sn9c102_i2c_write(cam, 0x67, 0x80);
|
||||
err += sn9c102_i2c_write(cam, 0x68, 0x7A);
|
||||
err += sn9c102_i2c_write(cam, 0x69, 0x90);
|
||||
err += sn9c102_i2c_write(cam, 0x6A, 0x80);
|
||||
err += sn9c102_i2c_write(cam, 0x6B, 0x0A);
|
||||
err += sn9c102_i2c_write(cam, 0x6C, 0x30);
|
||||
err += sn9c102_i2c_write(cam, 0x6D, 0x48);
|
||||
err += sn9c102_i2c_write(cam, 0x6E, 0x80);
|
||||
err += sn9c102_i2c_write(cam, 0x6F, 0x74);
|
||||
err += sn9c102_i2c_write(cam, 0x70, 0x64);
|
||||
err += sn9c102_i2c_write(cam, 0x71, 0x60);
|
||||
err += sn9c102_i2c_write(cam, 0x72, 0x5C);
|
||||
err += sn9c102_i2c_write(cam, 0x73, 0x58);
|
||||
err += sn9c102_i2c_write(cam, 0x74, 0x54);
|
||||
err += sn9c102_i2c_write(cam, 0x75, 0x4C);
|
||||
err += sn9c102_i2c_write(cam, 0x76, 0x40);
|
||||
err += sn9c102_i2c_write(cam, 0x77, 0x38);
|
||||
err += sn9c102_i2c_write(cam, 0x78, 0x34);
|
||||
err += sn9c102_i2c_write(cam, 0x79, 0x30);
|
||||
err += sn9c102_i2c_write(cam, 0x7A, 0x2F);
|
||||
err += sn9c102_i2c_write(cam, 0x7B, 0x2B);
|
||||
err += sn9c102_i2c_write(cam, 0x7C, 0x03);
|
||||
err += sn9c102_i2c_write(cam, 0x7D, 0x07);
|
||||
err += sn9c102_i2c_write(cam, 0x7E, 0x17);
|
||||
err += sn9c102_i2c_write(cam, 0x7F, 0x34);
|
||||
err += sn9c102_i2c_write(cam, 0x80, 0x41);
|
||||
err += sn9c102_i2c_write(cam, 0x81, 0x4D);
|
||||
err += sn9c102_i2c_write(cam, 0x82, 0x58);
|
||||
err += sn9c102_i2c_write(cam, 0x83, 0x63);
|
||||
err += sn9c102_i2c_write(cam, 0x84, 0x6E);
|
||||
err += sn9c102_i2c_write(cam, 0x85, 0x77);
|
||||
err += sn9c102_i2c_write(cam, 0x86, 0x87);
|
||||
err += sn9c102_i2c_write(cam, 0x87, 0x95);
|
||||
err += sn9c102_i2c_write(cam, 0x88, 0xAF);
|
||||
err += sn9c102_i2c_write(cam, 0x89, 0xC7);
|
||||
err += sn9c102_i2c_write(cam, 0x8A, 0xDF);
|
||||
err += sn9c102_i2c_write(cam, 0x8B, 0x99);
|
||||
err += sn9c102_i2c_write(cam, 0x8C, 0x99);
|
||||
err += sn9c102_i2c_write(cam, 0x8D, 0xCF);
|
||||
err += sn9c102_i2c_write(cam, 0x8E, 0x20);
|
||||
err += sn9c102_i2c_write(cam, 0x8F, 0x26);
|
||||
err += sn9c102_i2c_write(cam, 0x90, 0x10);
|
||||
err += sn9c102_i2c_write(cam, 0x91, 0x0C);
|
||||
err += sn9c102_i2c_write(cam, 0x92, 0x25);
|
||||
err += sn9c102_i2c_write(cam, 0x93, 0x00);
|
||||
err += sn9c102_i2c_write(cam, 0x94, 0x50);
|
||||
err += sn9c102_i2c_write(cam, 0x95, 0x50);
|
||||
err += sn9c102_i2c_write(cam, 0x96, 0x00);
|
||||
err += sn9c102_i2c_write(cam, 0x97, 0x01);
|
||||
err += sn9c102_i2c_write(cam, 0x98, 0x10);
|
||||
err += sn9c102_i2c_write(cam, 0x99, 0x40);
|
||||
err += sn9c102_i2c_write(cam, 0x9A, 0x40);
|
||||
err += sn9c102_i2c_write(cam, 0x9B, 0x20);
|
||||
err += sn9c102_i2c_write(cam, 0x9C, 0x00);
|
||||
err += sn9c102_i2c_write(cam, 0x9D, 0x99);
|
||||
err += sn9c102_i2c_write(cam, 0x9E, 0x7F);
|
||||
err += sn9c102_i2c_write(cam, 0x9F, 0x00);
|
||||
err += sn9c102_i2c_write(cam, 0xA0, 0x00);
|
||||
err += sn9c102_i2c_write(cam, 0xA1, 0x00);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static int ov7660_get_ctrl(struct sn9c102_device* cam,
|
||||
struct v4l2_control* ctrl)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_EXPOSURE:
|
||||
if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0)
|
||||
return -EIO;
|
||||
break;
|
||||
case V4L2_CID_DO_WHITE_BALANCE:
|
||||
ctrl->value = sn9c102_pread_reg(cam, 0x02);
|
||||
ctrl->value = (ctrl->value & 0x04) ? 1 : 0;
|
||||
break;
|
||||
case V4L2_CID_RED_BALANCE:
|
||||
ctrl->value = sn9c102_pread_reg(cam, 0x05);
|
||||
ctrl->value &= 0x7f;
|
||||
break;
|
||||
case V4L2_CID_BLUE_BALANCE:
|
||||
ctrl->value = sn9c102_pread_reg(cam, 0x06);
|
||||
ctrl->value &= 0x7f;
|
||||
break;
|
||||
case SN9C102_V4L2_CID_GREEN_BALANCE:
|
||||
ctrl->value = sn9c102_pread_reg(cam, 0x07);
|
||||
ctrl->value &= 0x7f;
|
||||
break;
|
||||
case V4L2_CID_GAIN:
|
||||
if ((ctrl->value = sn9c102_i2c_read(cam, 0x00)) < 0)
|
||||
return -EIO;
|
||||
ctrl->value &= 0x7f;
|
||||
break;
|
||||
case V4L2_CID_AUTOGAIN:
|
||||
if ((ctrl->value = sn9c102_i2c_read(cam, 0x13)) < 0)
|
||||
return -EIO;
|
||||
ctrl->value &= 0x01;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return err ? -EIO : 0;
|
||||
}
|
||||
|
||||
|
||||
static int ov7660_set_ctrl(struct sn9c102_device* cam,
|
||||
const struct v4l2_control* ctrl)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_EXPOSURE:
|
||||
err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
|
||||
break;
|
||||
case V4L2_CID_DO_WHITE_BALANCE:
|
||||
err += sn9c102_write_reg(cam, 0x43 | (ctrl->value << 2), 0x02);
|
||||
break;
|
||||
case V4L2_CID_RED_BALANCE:
|
||||
err += sn9c102_write_reg(cam, ctrl->value, 0x05);
|
||||
break;
|
||||
case V4L2_CID_BLUE_BALANCE:
|
||||
err += sn9c102_write_reg(cam, ctrl->value, 0x06);
|
||||
break;
|
||||
case SN9C102_V4L2_CID_GREEN_BALANCE:
|
||||
err += sn9c102_write_reg(cam, ctrl->value, 0x07);
|
||||
break;
|
||||
case V4L2_CID_GAIN:
|
||||
err += sn9c102_i2c_write(cam, 0x00, ctrl->value);
|
||||
break;
|
||||
case V4L2_CID_AUTOGAIN:
|
||||
err += sn9c102_i2c_write(cam, 0x13, 0xf0 | ctrl->value |
|
||||
(ctrl->value << 1));
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return err ? -EIO : 0;
|
||||
}
|
||||
|
||||
|
||||
static int ov7660_set_crop(struct sn9c102_device* cam,
|
||||
const struct v4l2_rect* rect)
|
||||
{
|
||||
struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
|
||||
int err = 0;
|
||||
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1,
|
||||
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
|
||||
|
||||
err += sn9c102_write_reg(cam, h_start, 0x12);
|
||||
err += sn9c102_write_reg(cam, v_start, 0x13);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static int ov7660_set_pix_format(struct sn9c102_device* cam,
|
||||
const struct v4l2_pix_format* pix)
|
||||
{
|
||||
int r0, err = 0;
|
||||
|
||||
r0 = sn9c102_pread_reg(cam, 0x01);
|
||||
|
||||
if (pix->pixelformat == V4L2_PIX_FMT_JPEG) {
|
||||
err += sn9c102_write_reg(cam, r0 | 0x40, 0x01);
|
||||
err += sn9c102_write_reg(cam, 0xa2, 0x17);
|
||||
err += sn9c102_i2c_write(cam, 0x11, 0x00);
|
||||
} else {
|
||||
err += sn9c102_write_reg(cam, r0 | 0x40, 0x01);
|
||||
err += sn9c102_write_reg(cam, 0xa2, 0x17);
|
||||
err += sn9c102_i2c_write(cam, 0x11, 0x0d);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static struct sn9c102_sensor ov7660 = {
|
||||
.name = "OV7660",
|
||||
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
|
||||
.supported_bridge = BRIDGE_SN9C105 | BRIDGE_SN9C120,
|
||||
.sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
|
||||
.frequency = SN9C102_I2C_100KHZ,
|
||||
.interface = SN9C102_I2C_2WIRES,
|
||||
.i2c_slave_id = 0x21,
|
||||
.init = &ov7660_init,
|
||||
.qctrl = {
|
||||
{
|
||||
.id = V4L2_CID_GAIN,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "global gain",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0x7f,
|
||||
.step = 0x01,
|
||||
.default_value = 0x0a,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_EXPOSURE,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "exposure",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0xff,
|
||||
.step = 0x01,
|
||||
.default_value = 0x50,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_DO_WHITE_BALANCE,
|
||||
.type = V4L2_CTRL_TYPE_BOOLEAN,
|
||||
.name = "night mode",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0x01,
|
||||
.step = 0x01,
|
||||
.default_value = 0x00,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_RED_BALANCE,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "red balance",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0x7f,
|
||||
.step = 0x01,
|
||||
.default_value = 0x1f,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_BLUE_BALANCE,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "blue balance",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0x7f,
|
||||
.step = 0x01,
|
||||
.default_value = 0x1e,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_AUTOGAIN,
|
||||
.type = V4L2_CTRL_TYPE_BOOLEAN,
|
||||
.name = "auto adjust",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0x01,
|
||||
.step = 0x01,
|
||||
.default_value = 0x00,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = SN9C102_V4L2_CID_GREEN_BALANCE,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "green balance",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0x7f,
|
||||
.step = 0x01,
|
||||
.default_value = 0x20,
|
||||
.flags = 0,
|
||||
},
|
||||
},
|
||||
.get_ctrl = &ov7660_get_ctrl,
|
||||
.set_ctrl = &ov7660_set_ctrl,
|
||||
.cropcap = {
|
||||
.bounds = {
|
||||
.left = 0,
|
||||
.top = 0,
|
||||
.width = 640,
|
||||
.height = 480,
|
||||
},
|
||||
.defrect = {
|
||||
.left = 0,
|
||||
.top = 0,
|
||||
.width = 640,
|
||||
.height = 480,
|
||||
},
|
||||
},
|
||||
.set_crop = &ov7660_set_crop,
|
||||
.pix_format = {
|
||||
.width = 640,
|
||||
.height = 480,
|
||||
.pixelformat = V4L2_PIX_FMT_JPEG,
|
||||
.priv = 8,
|
||||
},
|
||||
.set_pix_format = &ov7660_set_pix_format
|
||||
};
|
||||
|
||||
|
||||
int sn9c102_probe_ov7660(struct sn9c102_device* cam)
|
||||
{
|
||||
int pid, ver, err = 0;
|
||||
|
||||
err += sn9c102_write_reg(cam, 0x01, 0xf1);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0xf1);
|
||||
err += sn9c102_write_reg(cam, 0x01, 0x01);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x01);
|
||||
err += sn9c102_write_reg(cam, 0x28, 0x17);
|
||||
|
||||
pid = sn9c102_i2c_try_read(cam, &ov7660, 0x0a);
|
||||
ver = sn9c102_i2c_try_read(cam, &ov7660, 0x0b);
|
||||
if (err || pid < 0 || ver < 0)
|
||||
return -EIO;
|
||||
if (pid != 0x76 || ver != 0x60)
|
||||
return -ENODEV;
|
||||
sn9c102_attach_sensor(cam, &ov7660);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
/***************************************************************************
|
||||
* Plug-in for PAS106B image sensor connected to the SN9C10x PC Camera *
|
||||
* Plug-in for PAS106B image sensor connected to the SN9C1xx PC Camera *
|
||||
* Controllers *
|
||||
* *
|
||||
* Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
|
||||
* Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
|
@ -143,7 +143,7 @@ static int pas106b_set_ctrl(struct sn9c102_device* cam,
|
|||
static int pas106b_set_crop(struct sn9c102_device* cam,
|
||||
const struct v4l2_rect* rect)
|
||||
{
|
||||
struct sn9c102_sensor* s = &pas106b;
|
||||
struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
|
||||
int err = 0;
|
||||
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4,
|
||||
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
|
||||
|
@ -172,6 +172,7 @@ static int pas106b_set_pix_format(struct sn9c102_device* cam,
|
|||
static struct sn9c102_sensor pas106b = {
|
||||
.name = "PAS106B",
|
||||
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
|
||||
.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
|
||||
.sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
|
||||
.frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
|
||||
.interface = SN9C102_I2C_2WIRES,
|
||||
|
|
|
@ -1,238 +0,0 @@
|
|||
/***************************************************************************
|
||||
* Plug-in for PAS202BCA image sensor connected to the SN9C10x PC Camera *
|
||||
* Controllers *
|
||||
* *
|
||||
* Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the Free Software *
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include "sn9c102_sensor.h"
|
||||
|
||||
|
||||
static struct sn9c102_sensor pas202bca;
|
||||
|
||||
|
||||
static int pas202bca_init(struct sn9c102_device* cam)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x10);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x11);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x14);
|
||||
err += sn9c102_write_reg(cam, 0x20, 0x17);
|
||||
err += sn9c102_write_reg(cam, 0x30, 0x19);
|
||||
err += sn9c102_write_reg(cam, 0x09, 0x18);
|
||||
|
||||
err += sn9c102_i2c_write(cam, 0x02, 0x14);
|
||||
err += sn9c102_i2c_write(cam, 0x03, 0x40);
|
||||
err += sn9c102_i2c_write(cam, 0x0d, 0x2c);
|
||||
err += sn9c102_i2c_write(cam, 0x0e, 0x01);
|
||||
err += sn9c102_i2c_write(cam, 0x0f, 0xa9);
|
||||
err += sn9c102_i2c_write(cam, 0x10, 0x08);
|
||||
err += sn9c102_i2c_write(cam, 0x13, 0x63);
|
||||
err += sn9c102_i2c_write(cam, 0x15, 0x70);
|
||||
err += sn9c102_i2c_write(cam, 0x11, 0x01);
|
||||
|
||||
msleep(400);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static int pas202bca_set_pix_format(struct sn9c102_device* cam,
|
||||
const struct v4l2_pix_format* pix)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
|
||||
err += sn9c102_write_reg(cam, 0x24, 0x17);
|
||||
else
|
||||
err += sn9c102_write_reg(cam, 0x20, 0x17);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static int pas202bca_set_ctrl(struct sn9c102_device* cam,
|
||||
const struct v4l2_control* ctrl)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_EXPOSURE:
|
||||
err += sn9c102_i2c_write(cam, 0x04, ctrl->value >> 6);
|
||||
err += sn9c102_i2c_write(cam, 0x05, ctrl->value & 0x3f);
|
||||
break;
|
||||
case V4L2_CID_RED_BALANCE:
|
||||
err += sn9c102_i2c_write(cam, 0x09, ctrl->value);
|
||||
break;
|
||||
case V4L2_CID_BLUE_BALANCE:
|
||||
err += sn9c102_i2c_write(cam, 0x07, ctrl->value);
|
||||
break;
|
||||
case V4L2_CID_GAIN:
|
||||
err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
|
||||
break;
|
||||
case SN9C102_V4L2_CID_GREEN_BALANCE:
|
||||
err += sn9c102_i2c_write(cam, 0x08, ctrl->value);
|
||||
break;
|
||||
case SN9C102_V4L2_CID_DAC_MAGNITUDE:
|
||||
err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
err += sn9c102_i2c_write(cam, 0x11, 0x01);
|
||||
|
||||
return err ? -EIO : 0;
|
||||
}
|
||||
|
||||
|
||||
static int pas202bca_set_crop(struct sn9c102_device* cam,
|
||||
const struct v4l2_rect* rect)
|
||||
{
|
||||
struct sn9c102_sensor* s = &pas202bca;
|
||||
int err = 0;
|
||||
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 3,
|
||||
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
|
||||
|
||||
err += sn9c102_write_reg(cam, h_start, 0x12);
|
||||
err += sn9c102_write_reg(cam, v_start, 0x13);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static struct sn9c102_sensor pas202bca = {
|
||||
.name = "PAS202BCA",
|
||||
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
|
||||
.sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
|
||||
.frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
|
||||
.interface = SN9C102_I2C_2WIRES,
|
||||
.i2c_slave_id = 0x40,
|
||||
.init = &pas202bca_init,
|
||||
.qctrl = {
|
||||
{
|
||||
.id = V4L2_CID_EXPOSURE,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "exposure",
|
||||
.minimum = 0x01e5,
|
||||
.maximum = 0x3fff,
|
||||
.step = 0x0001,
|
||||
.default_value = 0x01e5,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_GAIN,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "global gain",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0x1f,
|
||||
.step = 0x01,
|
||||
.default_value = 0x0c,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_RED_BALANCE,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "red balance",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0x0f,
|
||||
.step = 0x01,
|
||||
.default_value = 0x01,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_BLUE_BALANCE,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "blue balance",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0x0f,
|
||||
.step = 0x01,
|
||||
.default_value = 0x05,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = SN9C102_V4L2_CID_GREEN_BALANCE,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "green balance",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0x0f,
|
||||
.step = 0x01,
|
||||
.default_value = 0x00,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = SN9C102_V4L2_CID_DAC_MAGNITUDE,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "DAC magnitude",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0xff,
|
||||
.step = 0x01,
|
||||
.default_value = 0x04,
|
||||
.flags = 0,
|
||||
},
|
||||
},
|
||||
.set_ctrl = &pas202bca_set_ctrl,
|
||||
.cropcap = {
|
||||
.bounds = {
|
||||
.left = 0,
|
||||
.top = 0,
|
||||
.width = 640,
|
||||
.height = 480,
|
||||
},
|
||||
.defrect = {
|
||||
.left = 0,
|
||||
.top = 0,
|
||||
.width = 640,
|
||||
.height = 480,
|
||||
},
|
||||
},
|
||||
.set_crop = &pas202bca_set_crop,
|
||||
.pix_format = {
|
||||
.width = 640,
|
||||
.height = 480,
|
||||
.pixelformat = V4L2_PIX_FMT_SBGGR8,
|
||||
.priv = 8,
|
||||
},
|
||||
.set_pix_format = &pas202bca_set_pix_format
|
||||
};
|
||||
|
||||
|
||||
int sn9c102_probe_pas202bca(struct sn9c102_device* cam)
|
||||
{
|
||||
const struct usb_device_id pas202bca_id_table[] = {
|
||||
{ USB_DEVICE(0x0c45, 0x60af), },
|
||||
{ }
|
||||
};
|
||||
int err = 0;
|
||||
|
||||
if (!sn9c102_match_id(cam,pas202bca_id_table))
|
||||
return -ENODEV;
|
||||
|
||||
err += sn9c102_write_reg(cam, 0x01, 0x01);
|
||||
err += sn9c102_write_reg(cam, 0x40, 0x01);
|
||||
err += sn9c102_write_reg(cam, 0x28, 0x17);
|
||||
if (err)
|
||||
return -EIO;
|
||||
|
||||
if (sn9c102_i2c_try_write(cam, &pas202bca, 0x10, 0)) /* try to write */
|
||||
return -ENODEV;
|
||||
|
||||
sn9c102_attach_sensor(cam, &pas202bca);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,13 +1,13 @@
|
|||
/***************************************************************************
|
||||
* Plug-in for PAS202BCB image sensor connected to the SN9C10x PC Camera *
|
||||
* Plug-in for PAS202BCB image sensor connected to the SN9C1xx PC Camera *
|
||||
* Controllers *
|
||||
* *
|
||||
* Copyright (C) 2004 by Carlos Eduardo Medaglia Dyonisio *
|
||||
* <medaglia@undl.org.br> *
|
||||
* http://cadu.homelinux.com:8080/ *
|
||||
* *
|
||||
* DAC Magnitude, exposure and green gain controls added by *
|
||||
* Luca Risolia <luca.risolia@studio.unibo.it> *
|
||||
* Support for SN9C103, DAC Magnitude, exposure and green gain controls *
|
||||
* added by Luca Risolia <luca.risolia@studio.unibo.it> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
|
@ -35,12 +35,54 @@ static int pas202bcb_init(struct sn9c102_device* cam)
|
|||
{
|
||||
int err = 0;
|
||||
|
||||
switch (sn9c102_get_bridge(cam)) {
|
||||
case BRIDGE_SN9C101:
|
||||
case BRIDGE_SN9C102:
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x10);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x11);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x14);
|
||||
err += sn9c102_write_reg(cam, 0x20, 0x17);
|
||||
err += sn9c102_write_reg(cam, 0x30, 0x19);
|
||||
err += sn9c102_write_reg(cam, 0x09, 0x18);
|
||||
break;
|
||||
case BRIDGE_SN9C103:
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x02);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x03);
|
||||
err += sn9c102_write_reg(cam, 0x1a, 0x04);
|
||||
err += sn9c102_write_reg(cam, 0x20, 0x05);
|
||||
err += sn9c102_write_reg(cam, 0x20, 0x06);
|
||||
err += sn9c102_write_reg(cam, 0x20, 0x07);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x10);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x11);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x14);
|
||||
err += sn9c102_write_reg(cam, 0x20, 0x17);
|
||||
err += sn9c102_write_reg(cam, 0x30, 0x19);
|
||||
err += sn9c102_write_reg(cam, 0x09, 0x18);
|
||||
err += sn9c102_write_reg(cam, 0x02, 0x1c);
|
||||
err += sn9c102_write_reg(cam, 0x03, 0x1d);
|
||||
err += sn9c102_write_reg(cam, 0x0f, 0x1e);
|
||||
err += sn9c102_write_reg(cam, 0x0c, 0x1f);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x20);
|
||||
err += sn9c102_write_reg(cam, 0x10, 0x21);
|
||||
err += sn9c102_write_reg(cam, 0x20, 0x22);
|
||||
err += sn9c102_write_reg(cam, 0x30, 0x23);
|
||||
err += sn9c102_write_reg(cam, 0x40, 0x24);
|
||||
err += sn9c102_write_reg(cam, 0x50, 0x25);
|
||||
err += sn9c102_write_reg(cam, 0x60, 0x26);
|
||||
err += sn9c102_write_reg(cam, 0x70, 0x27);
|
||||
err += sn9c102_write_reg(cam, 0x80, 0x28);
|
||||
err += sn9c102_write_reg(cam, 0x90, 0x29);
|
||||
err += sn9c102_write_reg(cam, 0xa0, 0x2a);
|
||||
err += sn9c102_write_reg(cam, 0xb0, 0x2b);
|
||||
err += sn9c102_write_reg(cam, 0xc0, 0x2c);
|
||||
err += sn9c102_write_reg(cam, 0xd0, 0x2d);
|
||||
err += sn9c102_write_reg(cam, 0xe0, 0x2e);
|
||||
err += sn9c102_write_reg(cam, 0xf0, 0x2f);
|
||||
err += sn9c102_write_reg(cam, 0xff, 0x30);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
err += sn9c102_i2c_write(cam, 0x02, 0x14);
|
||||
err += sn9c102_i2c_write(cam, 0x03, 0x40);
|
||||
|
@ -107,7 +149,7 @@ static int pas202bcb_set_pix_format(struct sn9c102_device* cam,
|
|||
int err = 0;
|
||||
|
||||
if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
|
||||
err += sn9c102_write_reg(cam, 0x24, 0x17);
|
||||
err += sn9c102_write_reg(cam, 0x28, 0x17);
|
||||
else
|
||||
err += sn9c102_write_reg(cam, 0x20, 0x17);
|
||||
|
||||
|
@ -152,11 +194,23 @@ static int pas202bcb_set_ctrl(struct sn9c102_device* cam,
|
|||
static int pas202bcb_set_crop(struct sn9c102_device* cam,
|
||||
const struct v4l2_rect* rect)
|
||||
{
|
||||
struct sn9c102_sensor* s = &pas202bcb;
|
||||
struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
|
||||
int err = 0;
|
||||
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4,
|
||||
u8 h_start = 0,
|
||||
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
|
||||
|
||||
switch (sn9c102_get_bridge(cam)) {
|
||||
case BRIDGE_SN9C101:
|
||||
case BRIDGE_SN9C102:
|
||||
h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4;
|
||||
break;
|
||||
case BRIDGE_SN9C103:
|
||||
h_start = (u8)(rect->left - s->cropcap.bounds.left) + 3;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
err += sn9c102_write_reg(cam, h_start, 0x12);
|
||||
err += sn9c102_write_reg(cam, v_start, 0x13);
|
||||
|
||||
|
@ -166,8 +220,8 @@ static int pas202bcb_set_crop(struct sn9c102_device* cam,
|
|||
|
||||
static struct sn9c102_sensor pas202bcb = {
|
||||
.name = "PAS202BCB",
|
||||
.maintainer = "Carlos Eduardo Medaglia Dyonisio "
|
||||
"<medaglia@undl.org.br>",
|
||||
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
|
||||
.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
|
||||
.sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
|
||||
.frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
|
||||
.interface = SN9C102_I2C_2WIRES,
|
||||
|
@ -191,7 +245,7 @@ static struct sn9c102_sensor pas202bcb = {
|
|||
.minimum = 0x00,
|
||||
.maximum = 0x1f,
|
||||
.step = 0x01,
|
||||
.default_value = 0x0c,
|
||||
.default_value = 0x0b,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
|
@ -201,7 +255,7 @@ static struct sn9c102_sensor pas202bcb = {
|
|||
.minimum = 0x00,
|
||||
.maximum = 0x0f,
|
||||
.step = 0x01,
|
||||
.default_value = 0x01,
|
||||
.default_value = 0x00,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
|
@ -271,16 +325,27 @@ int sn9c102_probe_pas202bcb(struct sn9c102_device* cam)
|
|||
* Minimal initialization to enable the I2C communication
|
||||
* NOTE: do NOT change the values!
|
||||
*/
|
||||
err += sn9c102_write_reg(cam, 0x01, 0x01); /* sensor power down */
|
||||
err += sn9c102_write_reg(cam, 0x40, 0x01); /* sensor power on */
|
||||
err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 24 MHz */
|
||||
if (err)
|
||||
return -EIO;
|
||||
switch (sn9c102_get_bridge(cam)) {
|
||||
case BRIDGE_SN9C101:
|
||||
case BRIDGE_SN9C102:
|
||||
err += sn9c102_write_reg(cam, 0x01, 0x01); /* power down */
|
||||
err += sn9c102_write_reg(cam, 0x40, 0x01); /* power on */
|
||||
err += sn9c102_write_reg(cam, 0x28, 0x17); /* clock 24 MHz */
|
||||
break;
|
||||
case BRIDGE_SN9C103: /* do _not_ change anything! */
|
||||
err += sn9c102_write_reg(cam, 0x09, 0x01);
|
||||
err += sn9c102_write_reg(cam, 0x44, 0x01);
|
||||
err += sn9c102_write_reg(cam, 0x44, 0x02);
|
||||
err += sn9c102_write_reg(cam, 0x29, 0x17);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
r0 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x00);
|
||||
r1 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x01);
|
||||
|
||||
if (r0 < 0 || r1 < 0)
|
||||
if (err || r0 < 0 || r1 < 0)
|
||||
return -EIO;
|
||||
|
||||
pid = (r0 << 4) | ((r1 & 0xf0) >> 4);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/***************************************************************************
|
||||
* API for image sensors connected to the SN9C10x PC Camera Controllers *
|
||||
* API for image sensors connected to the SN9C1xx PC Camera Controllers *
|
||||
* *
|
||||
* Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
|
||||
* Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
|
@ -36,14 +36,13 @@ struct sn9c102_sensor;
|
|||
/*
|
||||
OVERVIEW.
|
||||
This is a small interface that allows you to add support for any CCD/CMOS
|
||||
image sensors connected to the SN9C10X bridges. The entire API is documented
|
||||
image sensors connected to the SN9C1XX bridges. The entire API is documented
|
||||
below. In the most general case, to support a sensor there are three steps
|
||||
you have to follow:
|
||||
1) define the main "sn9c102_sensor" structure by setting the basic fields;
|
||||
2) write a probing function to be called by the core module when the USB
|
||||
camera is recognized, then add both the USB ids and the name of that
|
||||
function to the two corresponding tables SENSOR_TABLE and ID_TABLE (see
|
||||
below);
|
||||
function to the two corresponding tables in sn9c102_devtable.h;
|
||||
3) implement the methods that you want/need (and fill the rest of the main
|
||||
structure accordingly).
|
||||
"sn9c102_pas106b.c" is an example of all this stuff. Remember that you do
|
||||
|
@ -54,42 +53,21 @@ struct sn9c102_sensor;
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/*
|
||||
Probing functions: on success, you must attach the sensor to the camera
|
||||
by calling sn9c102_attach_sensor() provided below.
|
||||
To enable the I2C communication, you might need to perform a really basic
|
||||
initialization of the SN9C10X chip by using the write function declared
|
||||
ahead.
|
||||
Functions must return 0 on success, the appropriate error otherwise.
|
||||
*/
|
||||
extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam);
|
||||
extern int sn9c102_probe_mi0343(struct sn9c102_device* cam);
|
||||
extern int sn9c102_probe_ov7630(struct sn9c102_device* cam);
|
||||
extern int sn9c102_probe_pas106b(struct sn9c102_device* cam);
|
||||
extern int sn9c102_probe_pas202bca(struct sn9c102_device* cam);
|
||||
extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam);
|
||||
extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam);
|
||||
extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam);
|
||||
|
||||
/*
|
||||
Add the above entries to this table. Be sure to add the entry in the right
|
||||
place, since, on failure, the next probing routine is called according to
|
||||
the order of the list below, from top to bottom.
|
||||
*/
|
||||
#define SN9C102_SENSOR_TABLE \
|
||||
static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = { \
|
||||
&sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */ \
|
||||
&sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */ \
|
||||
&sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */ \
|
||||
&sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */ \
|
||||
&sn9c102_probe_pas202bca, /* detection mostly based on USB pid/vid */ \
|
||||
&sn9c102_probe_ov7630, /* detection mostly based on USB pid/vid */ \
|
||||
&sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */ \
|
||||
&sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */ \
|
||||
NULL, \
|
||||
enum sn9c102_bridge {
|
||||
BRIDGE_SN9C101 = 0x01,
|
||||
BRIDGE_SN9C102 = 0x02,
|
||||
BRIDGE_SN9C103 = 0x04,
|
||||
BRIDGE_SN9C105 = 0x08,
|
||||
BRIDGE_SN9C120 = 0x10,
|
||||
};
|
||||
|
||||
/* Device identification */
|
||||
/* Return the bridge name */
|
||||
enum sn9c102_bridge sn9c102_get_bridge(struct sn9c102_device* cam);
|
||||
|
||||
/* Return a pointer the sensor struct attached to the camera */
|
||||
struct sn9c102_sensor* sn9c102_get_sensor(struct sn9c102_device* cam);
|
||||
|
||||
/* Identify a device */
|
||||
extern struct sn9c102_device*
|
||||
sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id);
|
||||
|
||||
|
@ -98,69 +76,9 @@ extern void
|
|||
sn9c102_attach_sensor(struct sn9c102_device* cam,
|
||||
struct sn9c102_sensor* sensor);
|
||||
|
||||
/*
|
||||
Each SN9C10x camera has proper PID/VID identifiers.
|
||||
SN9C103 supports multiple interfaces, but we only handle the video class
|
||||
interface.
|
||||
*/
|
||||
#define SN9C102_USB_DEVICE(vend, prod, intclass) \
|
||||
.match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
|
||||
USB_DEVICE_ID_MATCH_INT_CLASS, \
|
||||
.idVendor = (vend), \
|
||||
.idProduct = (prod), \
|
||||
.bInterfaceClass = (intclass)
|
||||
|
||||
#define SN9C102_ID_TABLE \
|
||||
static const struct usb_device_id sn9c102_id_table[] = { \
|
||||
{ USB_DEVICE(0x0c45, 0x6001), }, /* TAS5110C1B */ \
|
||||
{ USB_DEVICE(0x0c45, 0x6005), }, /* TAS5110C1B */ \
|
||||
{ USB_DEVICE(0x0c45, 0x6007), }, \
|
||||
{ USB_DEVICE(0x0c45, 0x6009), }, /* PAS106B */ \
|
||||
{ USB_DEVICE(0x0c45, 0x600d), }, /* PAS106B */ \
|
||||
{ USB_DEVICE(0x0c45, 0x6024), }, \
|
||||
{ USB_DEVICE(0x0c45, 0x6025), }, /* TAS5130D1B and TAS5110C1B */ \
|
||||
{ USB_DEVICE(0x0c45, 0x6028), }, /* PAS202BCB */ \
|
||||
{ USB_DEVICE(0x0c45, 0x6029), }, /* PAS106B */ \
|
||||
{ USB_DEVICE(0x0c45, 0x602a), }, /* HV7131D */ \
|
||||
{ USB_DEVICE(0x0c45, 0x602b), }, /* MI-0343 */ \
|
||||
{ USB_DEVICE(0x0c45, 0x602c), }, /* OV7630 */ \
|
||||
{ USB_DEVICE(0x0c45, 0x602d), }, \
|
||||
{ USB_DEVICE(0x0c45, 0x602e), }, /* OV7630 */ \
|
||||
{ USB_DEVICE(0x0c45, 0x6030), }, /* MI03x */ \
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x6080, 0xff), }, \
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x6082, 0xff), }, /* MI0343 & MI0360 */ \
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x6083, 0xff), }, /* HV7131[D|E1] */ \
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x6088, 0xff), }, \
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x608a, 0xff), }, \
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x608b, 0xff), }, \
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x608c, 0xff), }, /* HV7131/R */ \
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x608e, 0xff), }, /* CIS-VF10 */ \
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x608f, 0xff), }, /* OV7630 */ \
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60a0, 0xff), }, \
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60a2, 0xff), }, \
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60a3, 0xff), }, \
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60a8, 0xff), }, /* PAS106B */ \
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60aa, 0xff), }, /* TAS5130D1B */ \
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60ab, 0xff), }, /* TAS5110C1B */ \
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60ac, 0xff), }, \
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60ae, 0xff), }, \
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60af, 0xff), }, /* PAS202BCB */ \
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60b0, 0xff), }, /* OV7630 (?) */ \
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60b2, 0xff), }, \
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60b3, 0xff), }, \
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60b8, 0xff), }, \
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60ba, 0xff), }, \
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60bb, 0xff), }, \
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60bc, 0xff), }, \
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60be, 0xff), }, \
|
||||
{ } \
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/*
|
||||
Read/write routines: they always return -1 on error, 0 or the read value
|
||||
otherwise. NOTE that a real read operation is not supported by the SN9C10X
|
||||
otherwise. NOTE that a real read operation is not supported by the SN9C1XX
|
||||
chip for some of its registers. To work around this problem, a pseudo-read
|
||||
call is provided instead: it returns the last successfully written value
|
||||
on the register (0 if it has never been written), the usual -1 on error.
|
||||
|
@ -176,7 +94,7 @@ extern int sn9c102_i2c_try_read(struct sn9c102_device*,struct sn9c102_sensor*,
|
|||
These must be used if and only if the sensor doesn't implement the standard
|
||||
I2C protocol. There are a number of good reasons why you must use the
|
||||
single-byte versions of these functions: do not abuse. The first function
|
||||
writes n bytes, from data0 to datan, to registers 0x09 - 0x09+n of SN9C10X
|
||||
writes n bytes, from data0 to datan, to registers 0x09 - 0x09+n of SN9C1XX
|
||||
chip. The second one programs the registers 0x09 and 0x10 with data0 and
|
||||
data1, and places the n bytes read from the sensor register table in the
|
||||
buffer pointed by 'buffer'. Both the functions return -1 on error; the write
|
||||
|
@ -200,16 +118,6 @@ extern int sn9c102_write_regs(struct sn9c102_device*, u8* buff, u16 index);
|
|||
extern int sn9c102_write_reg(struct sn9c102_device*, u8 value, u16 index);
|
||||
extern int sn9c102_pread_reg(struct sn9c102_device*, u16 index);
|
||||
|
||||
/*
|
||||
NOTE: there are no exported debugging functions. To uniform the output you
|
||||
must use the dev_info()/dev_warn()/dev_err() macros defined in device.h,
|
||||
already included here, the argument being the struct device '&usbdev->dev'
|
||||
of the sensor structure. Do NOT use these macros before the sensor is
|
||||
attached or the kernel will crash! However, you should not need to notify
|
||||
the user about common errors or other messages, since this is done by the
|
||||
master module.
|
||||
*/
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
enum sn9c102_i2c_sysfs_ops {
|
||||
|
@ -227,17 +135,19 @@ enum sn9c102_i2c_interface {
|
|||
SN9C102_I2C_3WIRES,
|
||||
};
|
||||
|
||||
#define SN9C102_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10
|
||||
#define SN9C102_MAX_CTRLS (V4L2_CID_LASTP1-V4L2_CID_BASE+10)
|
||||
|
||||
struct sn9c102_sensor {
|
||||
char name[32], /* sensor name */
|
||||
maintainer[64]; /* name of the mantainer <email> */
|
||||
|
||||
enum sn9c102_bridge supported_bridge; /* supported SN9C1xx bridges */
|
||||
|
||||
/* Supported operations through the 'sysfs' interface */
|
||||
enum sn9c102_i2c_sysfs_ops sysfs_ops;
|
||||
|
||||
/*
|
||||
These sensor capabilities must be provided if the SN9C10X controller
|
||||
These sensor capabilities must be provided if the SN9C1XX controller
|
||||
needs to communicate through the sensor serial interface by using
|
||||
at least one of the i2c functions available.
|
||||
*/
|
||||
|
@ -260,7 +170,7 @@ struct sn9c102_sensor {
|
|||
/*
|
||||
This function will be called after the sensor has been attached.
|
||||
It should be used to initialize the sensor only, but may also
|
||||
configure part of the SN9C10X chip if necessary. You don't need to
|
||||
configure part of the SN9C1XX chip if necessary. You don't need to
|
||||
setup picture settings like brightness, contrast, etc.. here, if
|
||||
the corrisponding controls are implemented (see below), since
|
||||
they are adjusted in the core driver by calling the set_ctrl()
|
||||
|
@ -300,7 +210,7 @@ struct sn9c102_sensor {
|
|||
It is not always true that the largest achievable active window can
|
||||
cover the whole array of pixels. The V4L2 API defines another
|
||||
area called "source rectangle", which, in turn, is a subrectangle of
|
||||
the active window. The SN9C10X chip is always programmed to read the
|
||||
the active window. The SN9C1XX chip is always programmed to read the
|
||||
source rectangle.
|
||||
The bounds of both the active window and the source rectangle are
|
||||
specified in the cropcap substructures 'bounds' and 'defrect'.
|
||||
|
@ -326,13 +236,13 @@ struct sn9c102_sensor {
|
|||
const struct v4l2_rect* rect);
|
||||
/*
|
||||
To be called on VIDIOC_C_SETCROP. The core module always calls a
|
||||
default routine which configures the appropriate SN9C10X regs (also
|
||||
default routine which configures the appropriate SN9C1XX regs (also
|
||||
scaling), but you may need to override/adjust specific stuff.
|
||||
'rect' contains width and height values that are multiple of 16: in
|
||||
case you override the default function, you always have to program
|
||||
the chip to match those values; on error return the corresponding
|
||||
error code without rolling back.
|
||||
NOTE: in case, you must program the SN9C10X chip to get rid of
|
||||
NOTE: in case, you must program the SN9C1XX chip to get rid of
|
||||
blank pixels or blank lines at the _start_ of each line or
|
||||
frame after each HSYNC or VSYNC, so that the image starts with
|
||||
real RGB data (see regs 0x12, 0x13) (having set H_SIZE and,
|
||||
|
@ -344,16 +254,16 @@ struct sn9c102_sensor {
|
|||
/*
|
||||
What you have to define here are: 1) initial 'width' and 'height' of
|
||||
the target rectangle 2) the initial 'pixelformat', which can be
|
||||
either V4L2_PIX_FMT_SN9C10X (for compressed video) or
|
||||
V4L2_PIX_FMT_SBGGR8 3) 'priv', which we'll be used to indicate the
|
||||
number of bits per pixel for uncompressed video, 8 or 9 (despite the
|
||||
current value of 'pixelformat').
|
||||
either V4L2_PIX_FMT_SN9C10X, V4L2_PIX_FMT_JPEG (for ompressed video)
|
||||
or V4L2_PIX_FMT_SBGGR8 3) 'priv', which we'll be used to indicate
|
||||
the number of bits per pixel for uncompressed video, 8 or 9 (despite
|
||||
the current value of 'pixelformat').
|
||||
NOTE 1: both 'width' and 'height' _must_ be either 1/1 or 1/2 or 1/4
|
||||
of cropcap.defrect.width and cropcap.defrect.height. I
|
||||
suggest 1/1.
|
||||
NOTE 2: The initial compression quality is defined by the first bit
|
||||
of reg 0x17 during the initialization of the image sensor.
|
||||
NOTE 3: as said above, you have to program the SN9C10X chip to get
|
||||
NOTE 3: as said above, you have to program the SN9C1XX chip to get
|
||||
rid of any blank pixels, so that the output of the sensor
|
||||
matches the RGB bayer sequence (i.e. BGBGBG...GRGRGR).
|
||||
*/
|
||||
|
@ -378,12 +288,12 @@ struct sn9c102_sensor {
|
|||
/*****************************************************************************/
|
||||
|
||||
/* Private ioctl's for control settings supported by some image sensors */
|
||||
#define SN9C102_V4L2_CID_DAC_MAGNITUDE V4L2_CID_PRIVATE_BASE
|
||||
#define SN9C102_V4L2_CID_GREEN_BALANCE V4L2_CID_PRIVATE_BASE + 1
|
||||
#define SN9C102_V4L2_CID_RESET_LEVEL V4L2_CID_PRIVATE_BASE + 2
|
||||
#define SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE V4L2_CID_PRIVATE_BASE + 3
|
||||
#define SN9C102_V4L2_CID_GAMMA V4L2_CID_PRIVATE_BASE + 4
|
||||
#define SN9C102_V4L2_CID_BAND_FILTER V4L2_CID_PRIVATE_BASE + 5
|
||||
#define SN9C102_V4L2_CID_BRIGHT_LEVEL V4L2_CID_PRIVATE_BASE + 6
|
||||
#define SN9C102_V4L2_CID_DAC_MAGNITUDE (V4L2_CID_PRIVATE_BASE + 0)
|
||||
#define SN9C102_V4L2_CID_GREEN_BALANCE (V4L2_CID_PRIVATE_BASE + 1)
|
||||
#define SN9C102_V4L2_CID_RESET_LEVEL (V4L2_CID_PRIVATE_BASE + 2)
|
||||
#define SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE (V4L2_CID_PRIVATE_BASE + 3)
|
||||
#define SN9C102_V4L2_CID_GAMMA (V4L2_CID_PRIVATE_BASE + 4)
|
||||
#define SN9C102_V4L2_CID_BAND_FILTER (V4L2_CID_PRIVATE_BASE + 5)
|
||||
#define SN9C102_V4L2_CID_BRIGHT_LEVEL (V4L2_CID_PRIVATE_BASE + 6)
|
||||
|
||||
#endif /* _SN9C102_SENSOR_H_ */
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
/***************************************************************************
|
||||
* Plug-in for TAS5110C1B image sensor connected to the SN9C10x PC Camera *
|
||||
* Plug-in for TAS5110C1B image sensor connected to the SN9C1xx PC Camera *
|
||||
* Controllers *
|
||||
* *
|
||||
* Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
|
||||
* Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
|
@ -64,7 +64,7 @@ static int tas5110c1b_set_ctrl(struct sn9c102_device* cam,
|
|||
static int tas5110c1b_set_crop(struct sn9c102_device* cam,
|
||||
const struct v4l2_rect* rect)
|
||||
{
|
||||
struct sn9c102_sensor* s = &tas5110c1b;
|
||||
struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
|
||||
int err = 0;
|
||||
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 69,
|
||||
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 9;
|
||||
|
@ -98,6 +98,7 @@ static int tas5110c1b_set_pix_format(struct sn9c102_device* cam,
|
|||
static struct sn9c102_sensor tas5110c1b = {
|
||||
.name = "TAS5110C1B",
|
||||
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
|
||||
.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
|
||||
.sysfs_ops = SN9C102_I2C_WRITE,
|
||||
.frequency = SN9C102_I2C_100KHZ,
|
||||
.interface = SN9C102_I2C_3WIRES,
|
||||
|
@ -145,6 +146,7 @@ int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam)
|
|||
const struct usb_device_id tas5110c1b_id_table[] = {
|
||||
{ USB_DEVICE(0x0c45, 0x6001), },
|
||||
{ USB_DEVICE(0x0c45, 0x6005), },
|
||||
{ USB_DEVICE(0x0c45, 0x6007), },
|
||||
{ USB_DEVICE(0x0c45, 0x60ab), },
|
||||
{ }
|
||||
};
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
/***************************************************************************
|
||||
* Plug-in for TAS5130D1B image sensor connected to the SN9C10x PC Camera *
|
||||
* Plug-in for TAS5130D1B image sensor connected to the SN9C1xx PC Camera *
|
||||
* Controllers *
|
||||
* *
|
||||
* Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
|
||||
* Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
|
@ -65,7 +65,7 @@ static int tas5130d1b_set_ctrl(struct sn9c102_device* cam,
|
|||
static int tas5130d1b_set_crop(struct sn9c102_device* cam,
|
||||
const struct v4l2_rect* rect)
|
||||
{
|
||||
struct sn9c102_sensor* s = &tas5130d1b;
|
||||
struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
|
||||
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 104,
|
||||
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 12;
|
||||
int err = 0;
|
||||
|
@ -99,6 +99,7 @@ static int tas5130d1b_set_pix_format(struct sn9c102_device* cam,
|
|||
static struct sn9c102_sensor tas5130d1b = {
|
||||
.name = "TAS5130D1B",
|
||||
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
|
||||
.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
|
||||
.sysfs_ops = SN9C102_I2C_WRITE,
|
||||
.frequency = SN9C102_I2C_100KHZ,
|
||||
.interface = SN9C102_I2C_3WIRES,
|
||||
|
@ -154,6 +155,7 @@ static struct sn9c102_sensor tas5130d1b = {
|
|||
int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam)
|
||||
{
|
||||
const struct usb_device_id tas5130d1b_id_table[] = {
|
||||
{ USB_DEVICE(0x0c45, 0x6024), },
|
||||
{ USB_DEVICE(0x0c45, 0x6025), },
|
||||
{ USB_DEVICE(0x0c45, 0x60aa), },
|
||||
{ }
|
||||
|
|
Loading…
Reference in New Issue