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:
committed by
Mauro Carvalho Chehab
parent
19790db00b
commit
f327ebbd00
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
SN9C10x PC Camera Controllers
|
SN9C1xx PC Camera Controllers
|
||||||
Driver for Linux
|
Driver for Linux
|
||||||
=============================
|
=============================
|
||||||
|
|
||||||
@@ -53,20 +53,14 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|||||||
|
|
||||||
4. Overview and features
|
4. Overview and features
|
||||||
========================
|
========================
|
||||||
This driver attempts to support the video interface of the devices mounting the
|
This driver attempts to support the video interface of the devices assembling
|
||||||
SONiX SN9C101, SN9C102 and SN9C103 PC Camera Controllers.
|
the SONiX SN9C101, SN9C102, SN9C103, SN9C105 and SN9C120 PC Camera Controllers
|
||||||
|
("SN9C1xx" from now on).
|
||||||
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.
|
|
||||||
|
|
||||||
The driver relies on the Video4Linux2 and USB core modules. It has been
|
The driver relies on the Video4Linux2 and USB core modules. It has been
|
||||||
designed to run properly on SMP systems as well.
|
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/
|
http://www.linux-projects.org/
|
||||||
|
|
||||||
Some of the features of the driver are:
|
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"
|
high compression quality (see also "Notes for V4L2 application developers"
|
||||||
and "Video frame formats" paragraphs);
|
and "Video frame formats" paragraphs);
|
||||||
- full support for the capabilities of many of the possible image sensors that
|
- 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"
|
blue and global gain adjustments and exposure (see "Supported devices"
|
||||||
paragraph for details);
|
paragraph for details);
|
||||||
- use of default color settings for sunlight conditions;
|
- 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);
|
monitoring (see "Optional device control through 'sysfs'" paragraph);
|
||||||
- dynamic driver control thanks to various module parameters (see "Module
|
- dynamic driver control thanks to various module parameters (see "Module
|
||||||
parameters" paragraph);
|
parameters" paragraph);
|
||||||
@@ -130,8 +124,8 @@ necessary:
|
|||||||
CONFIG_USB_UHCI_HCD=m
|
CONFIG_USB_UHCI_HCD=m
|
||||||
CONFIG_USB_OHCI_HCD=m
|
CONFIG_USB_OHCI_HCD=m
|
||||||
|
|
||||||
The SN9C103 controller also provides a built-in microphone interface. It is
|
The SN9C103, SN9c105 and SN9C120 controllers also provide a built-in microphone
|
||||||
supported by the USB Audio driver thanks to the ALSA API:
|
interface. It is supported by the USB Audio driver thanks to the ALSA API:
|
||||||
|
|
||||||
# Sound
|
# Sound
|
||||||
#
|
#
|
||||||
@@ -155,18 +149,27 @@ And finally:
|
|||||||
6. Module loading
|
6. Module loading
|
||||||
=================
|
=================
|
||||||
To use the driver, it is necessary to load the "sn9c102" module into memory
|
To use the driver, it is necessary to load the "sn9c102" module into memory
|
||||||
after every other module required: "videodev", "usbcore" and, depending on
|
after every other module required: "videodev", "v4l2_common", "compat_ioctl32",
|
||||||
the USB host controller you have, "ehci-hcd", "uhci-hcd" or "ohci-hcd".
|
"usbcore" and, depending on the USB host controller you have, "ehci-hcd",
|
||||||
|
"uhci-hcd" or "ohci-hcd".
|
||||||
|
|
||||||
Loading can be done as shown below:
|
Loading can be done as shown below:
|
||||||
|
|
||||||
[root@localhost home]# modprobe sn9c102
|
[root@localhost home]# modprobe sn9c102
|
||||||
|
|
||||||
At this point the devices should be recognized. You can invoke "dmesg" to
|
Note that the module is called "sn9c102" for historic reasons, althought it
|
||||||
analyze kernel messages and verify that the loading process has gone well:
|
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
|
[user@localhost home]$ dmesg
|
||||||
|
|
||||||
|
or, to isolate all the kernel messages generated by the driver:
|
||||||
|
|
||||||
|
[user@localhost home]$ dmesg | grep sn9c102
|
||||||
|
|
||||||
|
|
||||||
7. Module parameters
|
7. Module parameters
|
||||||
====================
|
====================
|
||||||
@@ -198,10 +201,11 @@ Default: 0
|
|||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
Name: frame_timeout
|
Name: frame_timeout
|
||||||
Type: uint array (min = 0, max = 64)
|
Type: uint array (min = 0, max = 64)
|
||||||
Syntax: <n[,...]>
|
Syntax: <0|n[,...]>
|
||||||
Description: Timeout for a video frame in seconds. This parameter is
|
Description: Timeout for a video frame in seconds before returning an I/O
|
||||||
specific for each detected camera. This parameter can be
|
error; 0 for infinity. This parameter is specific for each
|
||||||
changed at runtime thanks to the /sys filesystem interface.
|
detected camera and can be changed at runtime thanks to the
|
||||||
|
/sys filesystem interface.
|
||||||
Default: 2
|
Default: 2
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
Name: debug
|
Name: debug
|
||||||
@@ -223,20 +227,21 @@ Default: 2
|
|||||||
8. Optional device control through "sysfs" [1]
|
8. Optional device control through "sysfs" [1]
|
||||||
==========================================
|
==========================================
|
||||||
If the kernel has been compiled with the CONFIG_VIDEO_ADV_DEBUG option enabled,
|
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.
|
registers by using the "sysfs" filesystem interface.
|
||||||
|
|
||||||
Every time a supported device is recognized, a write-only file named "green" is
|
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
|
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
|
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.
|
to 15 for the SN9C101 or SN9C102 bridges, from 0 to 127 for the SN9C103,
|
||||||
Similarly, only for SN9C103 controllers, blue and red gain control files are
|
SN9C105 and SN9C120 bridges.
|
||||||
available in the same directory, for which accepted values may range from 0 to
|
Similarly, only for the SN9C103, SN9C105 and SN9120 controllers, blue and red
|
||||||
127.
|
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:
|
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
|
"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
|
"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
|
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
|
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 0x11 > reg
|
||||||
[root@localhost #] echo 2 > val
|
[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
|
To avoid race conditions, all the I/O accesses to the above files are
|
||||||
serialized.
|
serialized.
|
||||||
|
|
||||||
The sysfs interface also provides the "frame_header" entry, which exports the
|
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
|
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
|
controllers. As an example, this additional information can be used by the user
|
||||||
application for implementing auto-exposure features via software.
|
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
|
Byte # Value or bits Description
|
||||||
------ ----- -----------
|
------ ------------- -----------
|
||||||
0x00 0xFF Frame synchronisation pattern.
|
0x00 0xFF Frame synchronisation pattern
|
||||||
0x01 0xFF Frame synchronisation pattern.
|
0x01 0xFF Frame synchronisation pattern
|
||||||
0x02 0x00 Frame synchronisation pattern.
|
0x02 0x00 Frame synchronisation pattern
|
||||||
0x03 0xC4 Frame synchronisation pattern.
|
0x03 0xC4 Frame synchronisation pattern
|
||||||
0x04 0xC4 Frame synchronisation pattern.
|
0x04 0xC4 Frame synchronisation pattern
|
||||||
0x05 0x96 Frame synchronisation pattern.
|
0x05 0x96 Frame synchronisation pattern
|
||||||
0x06 0xXX Unknown meaning. The exact value depends on the chip;
|
0x06 [3:0] Read channel gain control = (1+R_GAIN/8)
|
||||||
possible values are 0x00, 0x01 and 0x20.
|
[7:4] Blue channel gain control = (1+B_GAIN/8)
|
||||||
0x07 0xXX Variable value, whose bits are ff00uzzc, where ff is a
|
0x07 [ 0 ] Compression mode. 0=No compression, 1=Compression enabled
|
||||||
frame counter, u is unknown, zz is a size indicator
|
[2:1] Maximum scale factor for compression
|
||||||
(00 = VGA, 01 = SIF, 10 = QSIF) and c stands for
|
[ 3 ] 1 = USB fifo(2K bytes) is full
|
||||||
"compression enabled" (1 = yes, 0 = no).
|
[ 4 ] 1 = Digital gain is finish
|
||||||
0x08 0xXX Brightness sum inside Auto-Exposure area (low-byte).
|
[ 5 ] 1 = Exposure is finish
|
||||||
0x09 0xXX Brightness sum inside Auto-Exposure area (high-byte).
|
[7:6] Frame index
|
||||||
For a pure white image, this number will be equal to 500
|
0x08 [7:0] Y sum inside Auto-Exposure area (low-byte)
|
||||||
times the area of the specified AE area. For images
|
0x09 [7:0] Y sum inside Auto-Exposure area (high-byte)
|
||||||
that are not pure white, the value scales down according
|
where Y sum = (R/4 + 5G/16 + B/8) / 32
|
||||||
to relative whiteness.
|
0x0A [7:0] Y sum outside Auto-Exposure area (low-byte)
|
||||||
0x0A 0xXX Brightness sum outside Auto-Exposure area (low-byte).
|
0x0B [7:0] Y sum outside Auto-Exposure area (high-byte)
|
||||||
0x0B 0xXX Brightness sum outside Auto-Exposure area (high-byte).
|
where Y sum = (R/4 + 5G/16 + B/8) / 128
|
||||||
For a pure white image, this number will be equal to 125
|
0x0C 0xXX Not used
|
||||||
times the area outside of the specified AE area. For
|
0x0D 0xXX Not used
|
||||||
images that are not pure white, the value scales down
|
0x0E 0xXX Not used
|
||||||
according to relative whiteness.
|
0x0F 0xXX Not used
|
||||||
according to relative whiteness.
|
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
|
Byte # Value or bits Description
|
||||||
0x0D 0xXX Unknown meaning
|
------ ------------- -----------
|
||||||
0x0E 0xXX Unknown meaning
|
0x00 0xFF Frame synchronisation pattern
|
||||||
0x0F 0xXX Unknown meaning
|
0x01 0xFF Frame synchronisation pattern
|
||||||
0x10 0xXX Unknown meaning
|
0x02 0x00 Frame synchronisation pattern
|
||||||
0x11 0xXX Unknown meaning
|
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
|
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.
|
corresponds to 32 pixels.
|
||||||
|
|
||||||
[1] Part of the meaning of the frame header has been documented by Bertrik
|
[1] The frame headers exported by the SN9C105 and SN9C120 are not described.
|
||||||
Sikken.
|
|
||||||
|
|
||||||
|
|
||||||
9. Supported devices
|
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
|
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
|
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
|
Vendor ID Product ID
|
||||||
--------- ----------
|
--------- ----------
|
||||||
|
0x0471 0x0327
|
||||||
|
0x0471 0x0328
|
||||||
0x0c45 0x6001
|
0x0c45 0x6001
|
||||||
0x0c45 0x6005
|
0x0c45 0x6005
|
||||||
0x0c45 0x6007
|
0x0c45 0x6007
|
||||||
0x0c45 0x6009
|
0x0c45 0x6009
|
||||||
0x0c45 0x600d
|
0x0c45 0x600d
|
||||||
|
0x0c45 0x6011
|
||||||
|
0x0c45 0x6019
|
||||||
0x0c45 0x6024
|
0x0c45 0x6024
|
||||||
0x0c45 0x6025
|
0x0c45 0x6025
|
||||||
0x0c45 0x6028
|
0x0c45 0x6028
|
||||||
@@ -342,6 +374,7 @@ Vendor ID Product ID
|
|||||||
0x0c45 0x602d
|
0x0c45 0x602d
|
||||||
0x0c45 0x602e
|
0x0c45 0x602e
|
||||||
0x0c45 0x6030
|
0x0c45 0x6030
|
||||||
|
0x0c45 0x603f
|
||||||
0x0c45 0x6080
|
0x0c45 0x6080
|
||||||
0x0c45 0x6082
|
0x0c45 0x6082
|
||||||
0x0c45 0x6083
|
0x0c45 0x6083
|
||||||
@@ -368,24 +401,40 @@ Vendor ID Product ID
|
|||||||
0x0c45 0x60bb
|
0x0c45 0x60bb
|
||||||
0x0c45 0x60bc
|
0x0c45 0x60bc
|
||||||
0x0c45 0x60be
|
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
|
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;
|
until now only the ones that assemble the following image sensors are
|
||||||
kernel messages will always tell you whether this is the case:
|
supported; kernel messages will always tell you whether this is the case (see
|
||||||
|
"Module loading" paragraph):
|
||||||
|
|
||||||
Model Manufacturer
|
Model Manufacturer
|
||||||
----- ------------
|
----- ------------
|
||||||
HV7131D Hynix Semiconductor, Inc.
|
HV7131D Hynix Semiconductor, Inc.
|
||||||
MI-0343 Micron Technology, Inc.
|
MI-0343 Micron Technology, Inc.
|
||||||
OV7630 OmniVision Technologies, Inc.
|
OV7630 OmniVision Technologies, Inc.
|
||||||
|
OV7660 OmniVision Technologies, Inc.
|
||||||
PAS106B PixArt Imaging, Inc.
|
PAS106B PixArt Imaging, Inc.
|
||||||
PAS202BCA PixArt Imaging, Inc.
|
PAS202BCA PixArt Imaging, Inc.
|
||||||
PAS202BCB PixArt Imaging, Inc.
|
PAS202BCB PixArt Imaging, Inc.
|
||||||
TAS5110C1B Taiwan Advanced Sensor Corporation
|
TAS5110C1B Taiwan Advanced Sensor Corporation
|
||||||
TAS5130D1B Taiwan Advanced Sensor Corporation
|
TAS5130D1B Taiwan Advanced Sensor Corporation
|
||||||
|
|
||||||
All the available control settings of each image sensor are supported through
|
Some of the available control settings of each image sensor are supported
|
||||||
the V4L2 interface.
|
through the V4L2 interface.
|
||||||
|
|
||||||
Donations of new models for further testing and support would be much
|
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
|
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]
|
11. Video frame formats [1]
|
||||||
=======================
|
=======================
|
||||||
The SN9C10x PC Camera Controllers can send images in two possible video
|
The SN9C1xx PC Camera Controllers can send images in two possible video
|
||||||
formats over the USB: either native "Sequential RGB Bayer" or Huffman
|
formats over the USB: either native "Sequential RGB Bayer" or compressed.
|
||||||
compressed. The latter is used to achieve high frame rates. The current video
|
The compression is used to achieve high frame rates. With regard to the
|
||||||
format may be selected or queried from the user application by calling the
|
SN9C101, SN9C102 and SN9C103, the compression is based on the Huffman encoding
|
||||||
VIDIOC_S_FMT or VIDIOC_G_FMT ioctl's, as described in the V4L2 API
|
algorithm described below, while the SN9C105 and SN9C120 the compression is
|
||||||
specifications.
|
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
|
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
|
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)]
|
... G[n(m-2)] R[n(m-1)]
|
||||||
|
|
||||||
The above matrix also represents the sequential or progressive read-out mode of
|
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,
|
The Huffman compressed video frame consists of a bitstream that encodes for
|
||||||
or B pixel the difference between the value of the pixel itself and some
|
every R, G, or B pixel the difference between the value of the pixel itself and
|
||||||
reference pixel value. Pixels are organised in the Bayer pattern and the Bayer
|
some reference pixel value. Pixels are organised in the Bayer pattern and the
|
||||||
sub-pixels are tracked individually and alternatingly. For example, in the
|
Bayer sub-pixels are tracked individually and alternatingly. For example, in
|
||||||
first line values for the B and G1 pixels are alternatingly encoded, while in
|
the first line values for the B and G1 pixels are alternatingly encoded, while
|
||||||
the second line values for the G2 and R pixels are alternatingly encoded.
|
in the second line values for the G2 and R pixels are alternatingly encoded.
|
||||||
|
|
||||||
The pixel reference value is calculated as follows:
|
The pixel reference value is calculated as follows:
|
||||||
- the 4 top left pixels are encoded in raw uncompressed 8-bit format;
|
- 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.
|
decoding.
|
||||||
|
|
||||||
The algorithm purely describes the conversion from compressed Bayer code used
|
The algorithm purely describes the conversion from compressed Bayer code used
|
||||||
in the SN9C10x chips to uncompressed Bayer. Additional steps are required to
|
in the SN9C101, SN9C102 and SN9C103 chips to uncompressed Bayer. Additional
|
||||||
convert this to a color image (i.e. a color interpolation algorithm).
|
steps are required to convert this to a color image (i.e. a color interpolation
|
||||||
|
algorithm).
|
||||||
|
|
||||||
The following Huffman codes have been found:
|
The following Huffman codes have been found:
|
||||||
0: +0 (relative to reference pixel value)
|
0: +0 (relative to reference pixel value)
|
||||||
@@ -506,13 +559,18 @@ order):
|
|||||||
- Philippe Coval for having helped testing the PAS202BCA image sensor;
|
- Philippe Coval for having helped testing the PAS202BCA image sensor;
|
||||||
- Joao Rodrigo Fuzaro, Joao Limirio, Claudio Filho and Caio Begotti for the
|
- Joao Rodrigo Fuzaro, Joao Limirio, Claudio Filho and Caio Begotti for the
|
||||||
donation of a webcam;
|
donation of a webcam;
|
||||||
|
- Dennis Heitmann for the donation of a webcam;
|
||||||
- Jon Hollstrom 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
|
- Carlos Eduardo Medaglia Dyonisio, who added the support for the PAS202BCB
|
||||||
image sensor;
|
image sensor;
|
||||||
- Stefano Mozzi, who donated 45 EU;
|
- Stefano Mozzi, who donated 45 EU;
|
||||||
- Andrew Pearce for the donation of a webcam;
|
- 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
|
- 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;
|
- Mizuno Takafumi for the donation of a webcam;
|
||||||
- an "anonymous" donator (who didn't want his name to be revealed) for the
|
- an "anonymous" donator (who didn't want his name to be revealed) for the
|
||||||
donation of a webcam.
|
donation of a webcam.
|
||||||
|
- an anonymous donator for the donation of four webcams.
|
||||||
|
@@ -1,9 +1,9 @@
|
|||||||
config USB_SN9C102
|
config USB_SN9C102
|
||||||
tristate "USB SN9C10x PC Camera Controller support"
|
tristate "USB SN9C1xx PC Camera Controller support"
|
||||||
depends on USB && VIDEO_V4L1
|
depends on USB && VIDEO_V4L1
|
||||||
---help---
|
---help---
|
||||||
Say Y here if you want support for cameras based on SONiX SN9C101,
|
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.
|
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-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_pas202bcb.o sn9c102_tas5110c1b.o \
|
||||||
sn9c102_tas5130d1b.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> *
|
* Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
|
||||||
* *
|
* *
|
||||||
@@ -37,33 +37,10 @@
|
|||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/stddef.h>
|
#include <linux/stddef.h>
|
||||||
|
|
||||||
|
#include "sn9c102_config.h"
|
||||||
#include "sn9c102_sensor.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 {
|
enum sn9c102_frame_state {
|
||||||
F_UNUSED,
|
F_UNUSED,
|
||||||
@@ -99,13 +76,11 @@ enum sn9c102_stream_state {
|
|||||||
STREAM_ON,
|
STREAM_ON,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef char sn9c103_sof_header_t[18];
|
typedef char sn9c102_sof_header_t[62];
|
||||||
typedef char sn9c102_sof_header_t[12];
|
|
||||||
typedef char sn9c102_eof_header_t[4];
|
|
||||||
|
|
||||||
struct sn9c102_sysfs_attr {
|
struct sn9c102_sysfs_attr {
|
||||||
u8 reg, i2c_reg;
|
u8 reg, i2c_reg;
|
||||||
sn9c103_sof_header_t frame_header;
|
sn9c102_sof_header_t frame_header;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sn9c102_module_param {
|
struct sn9c102_module_param {
|
||||||
@@ -137,8 +112,8 @@ struct sn9c102_device {
|
|||||||
struct v4l2_jpegcompression compression;
|
struct v4l2_jpegcompression compression;
|
||||||
|
|
||||||
struct sn9c102_sysfs_attr sysfs;
|
struct sn9c102_sysfs_attr sysfs;
|
||||||
sn9c103_sof_header_t sof_header;
|
sn9c102_sof_header_t sof_header;
|
||||||
u16 reg[63];
|
u16 reg[384];
|
||||||
|
|
||||||
struct sn9c102_module_param module_param;
|
struct sn9c102_module_param module_param;
|
||||||
|
|
||||||
@@ -155,10 +130,7 @@ struct sn9c102_device {
|
|||||||
struct sn9c102_device*
|
struct sn9c102_device*
|
||||||
sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id)
|
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 usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id) ? cam : NULL;
|
||||||
return cam;
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -169,6 +141,19 @@ sn9c102_attach_sensor(struct sn9c102_device* cam,
|
|||||||
memcpy(&cam->sensor, sensor, sizeof(struct sn9c102_sensor));
|
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
|
#undef DBG
|
||||||
|
86
drivers/media/video/sn9c102/sn9c102_config.h
Normal file
86
drivers/media/video/sn9c102/sn9c102_config.h
Normal file
@@ -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
142
drivers/media/video/sn9c102/sn9c102_devtable.h
Normal file
142
drivers/media/video/sn9c102/sn9c102_devtable.h
Normal file
@@ -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 *
|
* 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 *
|
* 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 *
|
* 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,
|
static int hv7131d_set_crop(struct sn9c102_device* cam,
|
||||||
const struct v4l2_rect* rect)
|
const struct v4l2_rect* rect)
|
||||||
{
|
{
|
||||||
struct sn9c102_sensor* s = &hv7131d;
|
struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
|
||||||
int err = 0;
|
int err = 0;
|
||||||
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 2,
|
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 2,
|
||||||
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 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 = {
|
static struct sn9c102_sensor hv7131d = {
|
||||||
.name = "HV7131D",
|
.name = "HV7131D",
|
||||||
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
|
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
|
||||||
|
.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
|
||||||
.sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
|
.sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
|
||||||
.frequency = SN9C102_I2C_100KHZ,
|
.frequency = SN9C102_I2C_100KHZ,
|
||||||
.interface = SN9C102_I2C_2WIRES,
|
.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 *
|
* 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 *
|
* 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 *
|
* 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,
|
static int mi0343_set_crop(struct sn9c102_device* cam,
|
||||||
const struct v4l2_rect* rect)
|
const struct v4l2_rect* rect)
|
||||||
{
|
{
|
||||||
struct sn9c102_sensor* s = &mi0343;
|
struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
|
||||||
int err = 0;
|
int err = 0;
|
||||||
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 0,
|
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 0,
|
||||||
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2;
|
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 = {
|
static struct sn9c102_sensor mi0343 = {
|
||||||
.name = "MI-0343",
|
.name = "MI-0343",
|
||||||
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
|
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
|
||||||
|
.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
|
||||||
.frequency = SN9C102_I2C_100KHZ,
|
.frequency = SN9C102_I2C_100KHZ,
|
||||||
.interface = SN9C102_I2C_2WIRES,
|
.interface = SN9C102_I2C_2WIRES,
|
||||||
.i2c_slave_id = 0x5d,
|
.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 *
|
* 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 *
|
* 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 *
|
* 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;
|
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, 0x00, 0x14);
|
||||||
err += sn9c102_write_reg(cam, 0x60, 0x17);
|
err += sn9c102_write_reg(cam, 0x60, 0x17);
|
||||||
err += sn9c102_write_reg(cam, 0x0f, 0x18);
|
err += sn9c102_write_reg(cam, 0x0f, 0x18);
|
||||||
err += sn9c102_write_reg(cam, 0x50, 0x19);
|
err += sn9c102_write_reg(cam, 0x50, 0x19);
|
||||||
|
|
||||||
err += sn9c102_i2c_write(cam, 0x12, 0x80);
|
err += sn9c102_i2c_write(cam, 0x12, 0x8d);
|
||||||
err += sn9c102_i2c_write(cam, 0x11, 0x01);
|
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, 0x15, 0x34);
|
||||||
err += sn9c102_i2c_write(cam, 0x16, 0x03);
|
err += sn9c102_i2c_write(cam, 0x16, 0x03);
|
||||||
err += sn9c102_i2c_write(cam, 0x17, 0x1c);
|
err += sn9c102_i2c_write(cam, 0x17, 0x1c);
|
||||||
@@ -43,14 +47,12 @@ static int ov7630_init(struct sn9c102_device* cam)
|
|||||||
err += sn9c102_i2c_write(cam, 0x19, 0x06);
|
err += sn9c102_i2c_write(cam, 0x19, 0x06);
|
||||||
err += sn9c102_i2c_write(cam, 0x1a, 0xf6);
|
err += sn9c102_i2c_write(cam, 0x1a, 0xf6);
|
||||||
err += sn9c102_i2c_write(cam, 0x1b, 0x04);
|
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, 0x23, 0xee);
|
||||||
err += sn9c102_i2c_write(cam, 0x26, 0xa0);
|
err += sn9c102_i2c_write(cam, 0x26, 0xa0);
|
||||||
err += sn9c102_i2c_write(cam, 0x27, 0x9a);
|
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, 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, 0x2f, 0x3d);
|
||||||
err += sn9c102_i2c_write(cam, 0x30, 0x24);
|
err += sn9c102_i2c_write(cam, 0x30, 0x24);
|
||||||
err += sn9c102_i2c_write(cam, 0x32, 0x86);
|
err += sn9c102_i2c_write(cam, 0x32, 0x86);
|
||||||
@@ -63,11 +65,137 @@ static int ov7630_init(struct sn9c102_device* cam)
|
|||||||
err += sn9c102_i2c_write(cam, 0x71, 0x00);
|
err += sn9c102_i2c_write(cam, 0x71, 0x00);
|
||||||
err += sn9c102_i2c_write(cam, 0x74, 0x21);
|
err += sn9c102_i2c_write(cam, 0x74, 0x21);
|
||||||
err += sn9c102_i2c_write(cam, 0x7d, 0xf7);
|
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, 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;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return err;
|
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,
|
static int ov7630_set_ctrl(struct sn9c102_device* cam,
|
||||||
const struct v4l2_control* ctrl)
|
const struct v4l2_control* ctrl)
|
||||||
{
|
{
|
||||||
@@ -75,57 +203,35 @@ static int ov7630_set_ctrl(struct sn9c102_device* cam,
|
|||||||
|
|
||||||
switch (ctrl->id) {
|
switch (ctrl->id) {
|
||||||
case V4L2_CID_EXPOSURE:
|
case V4L2_CID_EXPOSURE:
|
||||||
err += sn9c102_i2c_write(cam, 0x10, ctrl->value >> 2);
|
err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
|
||||||
err += sn9c102_i2c_write(cam, 0x76, ctrl->value & 0x03);
|
|
||||||
break;
|
break;
|
||||||
case V4L2_CID_RED_BALANCE:
|
case V4L2_CID_RED_BALANCE:
|
||||||
err += sn9c102_i2c_write(cam, 0x02, ctrl->value);
|
err += sn9c102_write_reg(cam, ctrl->value, 0x07);
|
||||||
break;
|
break;
|
||||||
case V4L2_CID_BLUE_BALANCE:
|
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;
|
break;
|
||||||
case V4L2_CID_GAIN:
|
case V4L2_CID_GAIN:
|
||||||
err += sn9c102_i2c_write(cam, 0x00, ctrl->value);
|
err += sn9c102_i2c_write(cam, 0x00, ctrl->value);
|
||||||
break;
|
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:
|
case V4L2_CID_DO_WHITE_BALANCE:
|
||||||
err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
|
err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
|
||||||
break;
|
break;
|
||||||
case V4L2_CID_WHITENESS:
|
case V4L2_CID_WHITENESS:
|
||||||
err += sn9c102_i2c_write(cam, 0x0d, ctrl->value);
|
err += sn9c102_i2c_write(cam, 0x0d, ctrl->value);
|
||||||
break;
|
break;
|
||||||
case V4L2_CID_AUTO_WHITE_BALANCE:
|
|
||||||
err += sn9c102_i2c_write(cam, 0x12, (ctrl->value << 2) | 0x78);
|
|
||||||
break;
|
|
||||||
case V4L2_CID_AUTOGAIN:
|
case V4L2_CID_AUTOGAIN:
|
||||||
err += sn9c102_i2c_write(cam, 0x13, ctrl->value);
|
err += sn9c102_i2c_write(cam, 0x13, ctrl->value |
|
||||||
|
(ctrl->value << 1));
|
||||||
break;
|
break;
|
||||||
case V4L2_CID_VFLIP:
|
case V4L2_CID_VFLIP:
|
||||||
err += sn9c102_i2c_write(cam, 0x75, 0x0e | (ctrl->value << 7));
|
err += sn9c102_i2c_write(cam, 0x75, 0x0e | (ctrl->value << 7));
|
||||||
break;
|
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:
|
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;
|
break;
|
||||||
case SN9C102_V4L2_CID_BAND_FILTER:
|
case SN9C102_V4L2_CID_BAND_FILTER:
|
||||||
err += sn9c102_i2c_write(cam, 0x2d, ctrl->value << 2);
|
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,
|
static int ov7630_set_crop(struct sn9c102_device* cam,
|
||||||
const struct v4l2_rect* rect)
|
const struct v4l2_rect* rect)
|
||||||
{
|
{
|
||||||
struct sn9c102_sensor* s = &ov7630;
|
struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
|
||||||
int err = 0;
|
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);
|
err += sn9c102_write_reg(cam, v_start, 0x13);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
@@ -168,7 +276,8 @@ static int ov7630_set_pix_format(struct sn9c102_device* cam,
|
|||||||
static struct sn9c102_sensor ov7630 = {
|
static struct sn9c102_sensor ov7630 = {
|
||||||
.name = "OV7630",
|
.name = "OV7630",
|
||||||
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
|
.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,
|
.frequency = SN9C102_I2C_100KHZ,
|
||||||
.interface = SN9C102_I2C_2WIRES,
|
.interface = SN9C102_I2C_2WIRES,
|
||||||
.i2c_slave_id = 0x21,
|
.i2c_slave_id = 0x21,
|
||||||
@@ -184,84 +293,14 @@ static struct sn9c102_sensor ov7630 = {
|
|||||||
.default_value = 0x14,
|
.default_value = 0x14,
|
||||||
.flags = 0,
|
.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,
|
.id = V4L2_CID_EXPOSURE,
|
||||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||||
.name = "exposure",
|
.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,
|
.minimum = 0x00,
|
||||||
.maximum = 0xff,
|
.maximum = 0xff,
|
||||||
.step = 0x01,
|
.step = 0x01,
|
||||||
.default_value = 0x3a,
|
.default_value = 0x60,
|
||||||
.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,
|
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -275,21 +314,41 @@ static struct sn9c102_sensor ov7630 = {
|
|||||||
.flags = 0,
|
.flags = 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.id = V4L2_CID_AUTO_WHITE_BALANCE,
|
.id = V4L2_CID_DO_WHITE_BALANCE,
|
||||||
.type = V4L2_CTRL_TYPE_BOOLEAN,
|
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||||
.name = "auto white balance",
|
.name = "white balance background: blue",
|
||||||
.minimum = 0x00,
|
.minimum = 0x00,
|
||||||
.maximum = 0x01,
|
.maximum = 0x3f,
|
||||||
.step = 0x01,
|
.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,
|
.flags = 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.id = V4L2_CID_AUTOGAIN,
|
.id = V4L2_CID_AUTOGAIN,
|
||||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
.type = V4L2_CTRL_TYPE_BOOLEAN,
|
||||||
.name = "gain & exposure mode",
|
.name = "auto adjust",
|
||||||
.minimum = 0x00,
|
.minimum = 0x00,
|
||||||
.maximum = 0x03,
|
.maximum = 0x01,
|
||||||
.step = 0x01,
|
.step = 0x01,
|
||||||
.default_value = 0x00,
|
.default_value = 0x00,
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
@@ -305,23 +364,13 @@ static struct sn9c102_sensor ov7630 = {
|
|||||||
.flags = 0,
|
.flags = 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.id = V4L2_CID_BLACK_LEVEL,
|
.id = SN9C102_V4L2_CID_GREEN_BALANCE,
|
||||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||||
.name = "black pixel ratio",
|
.name = "green balance",
|
||||||
.minimum = 0x01,
|
.minimum = 0x00,
|
||||||
.maximum = 0x9a,
|
.maximum = 0x7f,
|
||||||
.step = 0x01,
|
.step = 0x01,
|
||||||
.default_value = 0x8a,
|
.default_value = 0x20,
|
||||||
.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,
|
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -345,6 +394,7 @@ static struct sn9c102_sensor ov7630 = {
|
|||||||
.flags = 0,
|
.flags = 0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
.get_ctrl = &ov7630_get_ctrl,
|
||||||
.set_ctrl = &ov7630_set_ctrl,
|
.set_ctrl = &ov7630_set_ctrl,
|
||||||
.cropcap = {
|
.cropcap = {
|
||||||
.bounds = {
|
.bounds = {
|
||||||
@@ -364,7 +414,7 @@ static struct sn9c102_sensor ov7630 = {
|
|||||||
.pix_format = {
|
.pix_format = {
|
||||||
.width = 640,
|
.width = 640,
|
||||||
.height = 480,
|
.height = 480,
|
||||||
.pixelformat = V4L2_PIX_FMT_SBGGR8,
|
.pixelformat = V4L2_PIX_FMT_SN9C10X,
|
||||||
.priv = 8,
|
.priv = 8,
|
||||||
},
|
},
|
||||||
.set_pix_format = &ov7630_set_pix_format
|
.set_pix_format = &ov7630_set_pix_format
|
||||||
@@ -373,28 +423,36 @@ static struct sn9c102_sensor ov7630 = {
|
|||||||
|
|
||||||
int sn9c102_probe_ov7630(struct sn9c102_device* cam)
|
int sn9c102_probe_ov7630(struct sn9c102_device* cam)
|
||||||
{
|
{
|
||||||
const struct usb_device_id ov7630_id_table[] = {
|
int pid, ver, err = 0;
|
||||||
{ 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;
|
|
||||||
|
|
||||||
|
switch (sn9c102_get_bridge(cam)) {
|
||||||
|
case BRIDGE_SN9C101:
|
||||||
|
case BRIDGE_SN9C102:
|
||||||
err += sn9c102_write_reg(cam, 0x01, 0x01);
|
err += sn9c102_write_reg(cam, 0x01, 0x01);
|
||||||
err += sn9c102_write_reg(cam, 0x00, 0x01);
|
err += sn9c102_write_reg(cam, 0x00, 0x01);
|
||||||
err += sn9c102_write_reg(cam, 0x28, 0x17);
|
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;
|
return -EIO;
|
||||||
|
if (pid != 0x76 || ver != 0x31)
|
||||||
err += sn9c102_i2c_try_write(cam, &ov7630, 0x0b, 0);
|
|
||||||
if (err)
|
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
sn9c102_attach_sensor(cam, &ov7630);
|
sn9c102_attach_sensor(cam, &ov7630);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
592
drivers/media/video/sn9c102/sn9c102_ov7660.c
Normal file
592
drivers/media/video/sn9c102/sn9c102_ov7660.c
Normal file
@@ -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 *
|
* 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 *
|
* 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 *
|
* 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,
|
static int pas106b_set_crop(struct sn9c102_device* cam,
|
||||||
const struct v4l2_rect* rect)
|
const struct v4l2_rect* rect)
|
||||||
{
|
{
|
||||||
struct sn9c102_sensor* s = &pas106b;
|
struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
|
||||||
int err = 0;
|
int err = 0;
|
||||||
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4,
|
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4,
|
||||||
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
|
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 = {
|
static struct sn9c102_sensor pas106b = {
|
||||||
.name = "PAS106B",
|
.name = "PAS106B",
|
||||||
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
|
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
|
||||||
|
.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
|
||||||
.sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
|
.sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
|
||||||
.frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
|
.frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
|
||||||
.interface = SN9C102_I2C_2WIRES,
|
.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 *
|
* Controllers *
|
||||||
* *
|
* *
|
||||||
* Copyright (C) 2004 by Carlos Eduardo Medaglia Dyonisio *
|
* Copyright (C) 2004 by Carlos Eduardo Medaglia Dyonisio *
|
||||||
* <medaglia@undl.org.br> *
|
* <medaglia@undl.org.br> *
|
||||||
* http://cadu.homelinux.com:8080/ *
|
* http://cadu.homelinux.com:8080/ *
|
||||||
* *
|
* *
|
||||||
* DAC Magnitude, exposure and green gain controls added by *
|
* Support for SN9C103, DAC Magnitude, exposure and green gain controls *
|
||||||
* Luca Risolia <luca.risolia@studio.unibo.it> *
|
* added by Luca Risolia <luca.risolia@studio.unibo.it> *
|
||||||
* *
|
* *
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
* 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 *
|
* 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;
|
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, 0x10);
|
||||||
err += sn9c102_write_reg(cam, 0x00, 0x11);
|
err += sn9c102_write_reg(cam, 0x00, 0x11);
|
||||||
err += sn9c102_write_reg(cam, 0x00, 0x14);
|
err += sn9c102_write_reg(cam, 0x00, 0x14);
|
||||||
err += sn9c102_write_reg(cam, 0x20, 0x17);
|
err += sn9c102_write_reg(cam, 0x20, 0x17);
|
||||||
err += sn9c102_write_reg(cam, 0x30, 0x19);
|
err += sn9c102_write_reg(cam, 0x30, 0x19);
|
||||||
err += sn9c102_write_reg(cam, 0x09, 0x18);
|
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, 0x02, 0x14);
|
||||||
err += sn9c102_i2c_write(cam, 0x03, 0x40);
|
err += sn9c102_i2c_write(cam, 0x03, 0x40);
|
||||||
@@ -107,7 +149,7 @@ static int pas202bcb_set_pix_format(struct sn9c102_device* cam,
|
|||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
|
if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
|
||||||
err += sn9c102_write_reg(cam, 0x24, 0x17);
|
err += sn9c102_write_reg(cam, 0x28, 0x17);
|
||||||
else
|
else
|
||||||
err += sn9c102_write_reg(cam, 0x20, 0x17);
|
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,
|
static int pas202bcb_set_crop(struct sn9c102_device* cam,
|
||||||
const struct v4l2_rect* rect)
|
const struct v4l2_rect* rect)
|
||||||
{
|
{
|
||||||
struct sn9c102_sensor* s = &pas202bcb;
|
struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
|
||||||
int err = 0;
|
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;
|
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, h_start, 0x12);
|
||||||
err += sn9c102_write_reg(cam, v_start, 0x13);
|
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 = {
|
static struct sn9c102_sensor pas202bcb = {
|
||||||
.name = "PAS202BCB",
|
.name = "PAS202BCB",
|
||||||
.maintainer = "Carlos Eduardo Medaglia Dyonisio "
|
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
|
||||||
"<medaglia@undl.org.br>",
|
.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
|
||||||
.sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
|
.sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
|
||||||
.frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
|
.frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
|
||||||
.interface = SN9C102_I2C_2WIRES,
|
.interface = SN9C102_I2C_2WIRES,
|
||||||
@@ -191,7 +245,7 @@ static struct sn9c102_sensor pas202bcb = {
|
|||||||
.minimum = 0x00,
|
.minimum = 0x00,
|
||||||
.maximum = 0x1f,
|
.maximum = 0x1f,
|
||||||
.step = 0x01,
|
.step = 0x01,
|
||||||
.default_value = 0x0c,
|
.default_value = 0x0b,
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -201,7 +255,7 @@ static struct sn9c102_sensor pas202bcb = {
|
|||||||
.minimum = 0x00,
|
.minimum = 0x00,
|
||||||
.maximum = 0x0f,
|
.maximum = 0x0f,
|
||||||
.step = 0x01,
|
.step = 0x01,
|
||||||
.default_value = 0x01,
|
.default_value = 0x00,
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -271,16 +325,27 @@ int sn9c102_probe_pas202bcb(struct sn9c102_device* cam)
|
|||||||
* Minimal initialization to enable the I2C communication
|
* Minimal initialization to enable the I2C communication
|
||||||
* NOTE: do NOT change the values!
|
* NOTE: do NOT change the values!
|
||||||
*/
|
*/
|
||||||
err += sn9c102_write_reg(cam, 0x01, 0x01); /* sensor power down */
|
switch (sn9c102_get_bridge(cam)) {
|
||||||
err += sn9c102_write_reg(cam, 0x40, 0x01); /* sensor power on */
|
case BRIDGE_SN9C101:
|
||||||
err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 24 MHz */
|
case BRIDGE_SN9C102:
|
||||||
if (err)
|
err += sn9c102_write_reg(cam, 0x01, 0x01); /* power down */
|
||||||
return -EIO;
|
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);
|
r0 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x00);
|
||||||
r1 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x01);
|
r1 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x01);
|
||||||
|
|
||||||
if (r0 < 0 || r1 < 0)
|
if (err || r0 < 0 || r1 < 0)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
pid = (r0 << 4) | ((r1 & 0xf0) >> 4);
|
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 *
|
* 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 *
|
* it under the terms of the GNU General Public License as published by *
|
||||||
@@ -36,14 +36,13 @@ struct sn9c102_sensor;
|
|||||||
/*
|
/*
|
||||||
OVERVIEW.
|
OVERVIEW.
|
||||||
This is a small interface that allows you to add support for any CCD/CMOS
|
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
|
below. In the most general case, to support a sensor there are three steps
|
||||||
you have to follow:
|
you have to follow:
|
||||||
1) define the main "sn9c102_sensor" structure by setting the basic fields;
|
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
|
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
|
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
|
function to the two corresponding tables in sn9c102_devtable.h;
|
||||||
below);
|
|
||||||
3) implement the methods that you want/need (and fill the rest of the main
|
3) implement the methods that you want/need (and fill the rest of the main
|
||||||
structure accordingly).
|
structure accordingly).
|
||||||
"sn9c102_pas106b.c" is an example of all this stuff. Remember that you do
|
"sn9c102_pas106b.c" is an example of all this stuff. Remember that you do
|
||||||
@@ -54,42 +53,21 @@ struct sn9c102_sensor;
|
|||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
/*
|
enum sn9c102_bridge {
|
||||||
Probing functions: on success, you must attach the sensor to the camera
|
BRIDGE_SN9C101 = 0x01,
|
||||||
by calling sn9c102_attach_sensor() provided below.
|
BRIDGE_SN9C102 = 0x02,
|
||||||
To enable the I2C communication, you might need to perform a really basic
|
BRIDGE_SN9C103 = 0x04,
|
||||||
initialization of the SN9C10X chip by using the write function declared
|
BRIDGE_SN9C105 = 0x08,
|
||||||
ahead.
|
BRIDGE_SN9C120 = 0x10,
|
||||||
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, \
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* 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*
|
extern struct sn9c102_device*
|
||||||
sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id);
|
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,
|
sn9c102_attach_sensor(struct sn9c102_device* cam,
|
||||||
struct sn9c102_sensor* sensor);
|
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
|
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
|
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
|
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.
|
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
|
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
|
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
|
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
|
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
|
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
|
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_write_reg(struct sn9c102_device*, u8 value, u16 index);
|
||||||
extern int sn9c102_pread_reg(struct sn9c102_device*, 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 {
|
enum sn9c102_i2c_sysfs_ops {
|
||||||
@@ -227,17 +135,19 @@ enum sn9c102_i2c_interface {
|
|||||||
SN9C102_I2C_3WIRES,
|
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 {
|
struct sn9c102_sensor {
|
||||||
char name[32], /* sensor name */
|
char name[32], /* sensor name */
|
||||||
maintainer[64]; /* name of the mantainer <email> */
|
maintainer[64]; /* name of the mantainer <email> */
|
||||||
|
|
||||||
|
enum sn9c102_bridge supported_bridge; /* supported SN9C1xx bridges */
|
||||||
|
|
||||||
/* Supported operations through the 'sysfs' interface */
|
/* Supported operations through the 'sysfs' interface */
|
||||||
enum sn9c102_i2c_sysfs_ops sysfs_ops;
|
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
|
needs to communicate through the sensor serial interface by using
|
||||||
at least one of the i2c functions available.
|
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.
|
This function will be called after the sensor has been attached.
|
||||||
It should be used to initialize the sensor only, but may also
|
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
|
setup picture settings like brightness, contrast, etc.. here, if
|
||||||
the corrisponding controls are implemented (see below), since
|
the corrisponding controls are implemented (see below), since
|
||||||
they are adjusted in the core driver by calling the set_ctrl()
|
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
|
It is not always true that the largest achievable active window can
|
||||||
cover the whole array of pixels. The V4L2 API defines another
|
cover the whole array of pixels. The V4L2 API defines another
|
||||||
area called "source rectangle", which, in turn, is a subrectangle of
|
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.
|
source rectangle.
|
||||||
The bounds of both the active window and the source rectangle are
|
The bounds of both the active window and the source rectangle are
|
||||||
specified in the cropcap substructures 'bounds' and 'defrect'.
|
specified in the cropcap substructures 'bounds' and 'defrect'.
|
||||||
@@ -326,13 +236,13 @@ struct sn9c102_sensor {
|
|||||||
const struct v4l2_rect* rect);
|
const struct v4l2_rect* rect);
|
||||||
/*
|
/*
|
||||||
To be called on VIDIOC_C_SETCROP. The core module always calls a
|
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.
|
scaling), but you may need to override/adjust specific stuff.
|
||||||
'rect' contains width and height values that are multiple of 16: in
|
'rect' contains width and height values that are multiple of 16: in
|
||||||
case you override the default function, you always have to program
|
case you override the default function, you always have to program
|
||||||
the chip to match those values; on error return the corresponding
|
the chip to match those values; on error return the corresponding
|
||||||
error code without rolling back.
|
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
|
blank pixels or blank lines at the _start_ of each line or
|
||||||
frame after each HSYNC or VSYNC, so that the image starts with
|
frame after each HSYNC or VSYNC, so that the image starts with
|
||||||
real RGB data (see regs 0x12, 0x13) (having set H_SIZE and,
|
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
|
What you have to define here are: 1) initial 'width' and 'height' of
|
||||||
the target rectangle 2) the initial 'pixelformat', which can be
|
the target rectangle 2) the initial 'pixelformat', which can be
|
||||||
either V4L2_PIX_FMT_SN9C10X (for compressed video) or
|
either V4L2_PIX_FMT_SN9C10X, V4L2_PIX_FMT_JPEG (for ompressed video)
|
||||||
V4L2_PIX_FMT_SBGGR8 3) 'priv', which we'll be used to indicate the
|
or V4L2_PIX_FMT_SBGGR8 3) 'priv', which we'll be used to indicate
|
||||||
number of bits per pixel for uncompressed video, 8 or 9 (despite the
|
the number of bits per pixel for uncompressed video, 8 or 9 (despite
|
||||||
current value of 'pixelformat').
|
the current value of 'pixelformat').
|
||||||
NOTE 1: both 'width' and 'height' _must_ be either 1/1 or 1/2 or 1/4
|
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
|
of cropcap.defrect.width and cropcap.defrect.height. I
|
||||||
suggest 1/1.
|
suggest 1/1.
|
||||||
NOTE 2: The initial compression quality is defined by the first bit
|
NOTE 2: The initial compression quality is defined by the first bit
|
||||||
of reg 0x17 during the initialization of the image sensor.
|
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
|
rid of any blank pixels, so that the output of the sensor
|
||||||
matches the RGB bayer sequence (i.e. BGBGBG...GRGRGR).
|
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 */
|
/* 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_DAC_MAGNITUDE (V4L2_CID_PRIVATE_BASE + 0)
|
||||||
#define SN9C102_V4L2_CID_GREEN_BALANCE V4L2_CID_PRIVATE_BASE + 1
|
#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_RESET_LEVEL (V4L2_CID_PRIVATE_BASE + 2)
|
||||||
#define SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE V4L2_CID_PRIVATE_BASE + 3
|
#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_GAMMA (V4L2_CID_PRIVATE_BASE + 4)
|
||||||
#define SN9C102_V4L2_CID_BAND_FILTER V4L2_CID_PRIVATE_BASE + 5
|
#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_BRIGHT_LEVEL (V4L2_CID_PRIVATE_BASE + 6)
|
||||||
|
|
||||||
#endif /* _SN9C102_SENSOR_H_ */
|
#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 *
|
* 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 *
|
* 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 *
|
* 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,
|
static int tas5110c1b_set_crop(struct sn9c102_device* cam,
|
||||||
const struct v4l2_rect* rect)
|
const struct v4l2_rect* rect)
|
||||||
{
|
{
|
||||||
struct sn9c102_sensor* s = &tas5110c1b;
|
struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
|
||||||
int err = 0;
|
int err = 0;
|
||||||
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 69,
|
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 69,
|
||||||
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 9;
|
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 = {
|
static struct sn9c102_sensor tas5110c1b = {
|
||||||
.name = "TAS5110C1B",
|
.name = "TAS5110C1B",
|
||||||
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
|
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
|
||||||
|
.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
|
||||||
.sysfs_ops = SN9C102_I2C_WRITE,
|
.sysfs_ops = SN9C102_I2C_WRITE,
|
||||||
.frequency = SN9C102_I2C_100KHZ,
|
.frequency = SN9C102_I2C_100KHZ,
|
||||||
.interface = SN9C102_I2C_3WIRES,
|
.interface = SN9C102_I2C_3WIRES,
|
||||||
@@ -145,6 +146,7 @@ int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam)
|
|||||||
const struct usb_device_id tas5110c1b_id_table[] = {
|
const struct usb_device_id tas5110c1b_id_table[] = {
|
||||||
{ USB_DEVICE(0x0c45, 0x6001), },
|
{ USB_DEVICE(0x0c45, 0x6001), },
|
||||||
{ USB_DEVICE(0x0c45, 0x6005), },
|
{ USB_DEVICE(0x0c45, 0x6005), },
|
||||||
|
{ USB_DEVICE(0x0c45, 0x6007), },
|
||||||
{ USB_DEVICE(0x0c45, 0x60ab), },
|
{ 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 *
|
* 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 *
|
* 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 *
|
* 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,
|
static int tas5130d1b_set_crop(struct sn9c102_device* cam,
|
||||||
const struct v4l2_rect* rect)
|
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,
|
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 104,
|
||||||
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 12;
|
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 12;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
@@ -99,6 +99,7 @@ static int tas5130d1b_set_pix_format(struct sn9c102_device* cam,
|
|||||||
static struct sn9c102_sensor tas5130d1b = {
|
static struct sn9c102_sensor tas5130d1b = {
|
||||||
.name = "TAS5130D1B",
|
.name = "TAS5130D1B",
|
||||||
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
|
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
|
||||||
|
.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
|
||||||
.sysfs_ops = SN9C102_I2C_WRITE,
|
.sysfs_ops = SN9C102_I2C_WRITE,
|
||||||
.frequency = SN9C102_I2C_100KHZ,
|
.frequency = SN9C102_I2C_100KHZ,
|
||||||
.interface = SN9C102_I2C_3WIRES,
|
.interface = SN9C102_I2C_3WIRES,
|
||||||
@@ -154,6 +155,7 @@ static struct sn9c102_sensor tas5130d1b = {
|
|||||||
int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam)
|
int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam)
|
||||||
{
|
{
|
||||||
const struct usb_device_id tas5130d1b_id_table[] = {
|
const struct usb_device_id tas5130d1b_id_table[] = {
|
||||||
|
{ USB_DEVICE(0x0c45, 0x6024), },
|
||||||
{ USB_DEVICE(0x0c45, 0x6025), },
|
{ USB_DEVICE(0x0c45, 0x6025), },
|
||||||
{ USB_DEVICE(0x0c45, 0x60aa), },
|
{ USB_DEVICE(0x0c45, 0x60aa), },
|
||||||
{ }
|
{ }
|
||||||
|
Reference in New Issue
Block a user