V4L/DVB (5474): SN9C1xx driver updates
@ Don't assume that SOF headers can't cross packets boundaries @ Fix compression quality selection + Add support for MI-0360 image sensor * Documentation updates @ Fix sysfs @ MI0343 rewritten * HV7131R color fixes and add new ABLC control * Rename the archive from "sn9c102" to "sn9c1xx" * fix typos * better support for TAS5110D @ fix OV7630 wrong colors @ Don't return an error if no input buffers are enqueued yet on VIDIOC_STREAMON * Add informations about colorspaces * More appropriate error codes in case of failure of some system calls * More precise hardware detection * Add more informations about supported hardware in the documentation + More supported devices + Add support for HV7131R image sensor Signed-off-by: Luca Risolia <luca.risolia@studio.unibo.it> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
This commit is contained in:
Родитель
9ab7e323af
Коммит
f423b9a86a
|
@ -25,7 +25,7 @@ Index
|
|||
|
||||
1. Copyright
|
||||
============
|
||||
Copyright (C) 2004-2006 by Luca Risolia <luca.risolia@studio.unibo.it>
|
||||
Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it>
|
||||
|
||||
|
||||
2. Disclaimer
|
||||
|
@ -216,10 +216,10 @@ Description: Debugging information level, from 0 to 3:
|
|||
1 = critical errors
|
||||
2 = significant informations
|
||||
3 = more verbose messages
|
||||
Level 3 is useful for testing only, when only one device
|
||||
is used. It also shows some more informations about the
|
||||
hardware being detected. This parameter can be changed at
|
||||
runtime thanks to the /sys filesystem interface.
|
||||
Level 3 is useful for testing only. It also shows some more
|
||||
informations about the hardware being detected.
|
||||
This parameter can be changed at runtime thanks to the /sys
|
||||
filesystem interface.
|
||||
Default: 2
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
|
@ -235,7 +235,7 @@ created in the /sys/class/video4linux/videoX directory. You can set the green
|
|||
channel's gain by writing the desired value to it. The value may range from 0
|
||||
to 15 for the SN9C101 or SN9C102 bridges, from 0 to 127 for the SN9C103,
|
||||
SN9C105 and SN9C120 bridges.
|
||||
Similarly, only for the SN9C103, SN9C105 and SN9120 controllers, blue and red
|
||||
Similarly, only for the SN9C103, SN9C105 and SN9C120 controllers, blue and red
|
||||
gain control files are available in the same directory, for which accepted
|
||||
values may range from 0 to 127.
|
||||
|
||||
|
@ -402,38 +402,49 @@ Vendor ID Product ID
|
|||
0x0c45 0x60bc
|
||||
0x0c45 0x60be
|
||||
0x0c45 0x60c0
|
||||
0x0c45 0x60c2
|
||||
0x0c45 0x60c8
|
||||
0x0c45 0x60cc
|
||||
0x0c45 0x60ea
|
||||
0x0c45 0x60ec
|
||||
0x0c45 0x60ef
|
||||
0x0c45 0x60fa
|
||||
0x0c45 0x60fb
|
||||
0x0c45 0x60fc
|
||||
0x0c45 0x60fe
|
||||
0x0c45 0x6102
|
||||
0x0c45 0x6108
|
||||
0x0c45 0x610f
|
||||
0x0c45 0x6130
|
||||
0x0c45 0x6138
|
||||
0x0c45 0x613a
|
||||
0x0c45 0x613b
|
||||
0x0c45 0x613c
|
||||
0x0c45 0x613e
|
||||
|
||||
The list above does not imply that all those devices work with this driver: up
|
||||
until now only the ones that assemble the following image sensors are
|
||||
supported; kernel messages will always tell you whether this is the case (see
|
||||
"Module loading" paragraph):
|
||||
until now only the ones that assemble the following pairs of SN9C1xx bridges
|
||||
and image sensors are supported; kernel messages will always tell you whether
|
||||
this is the case (see "Module loading" paragraph):
|
||||
|
||||
Model Manufacturer
|
||||
----- ------------
|
||||
HV7131D Hynix Semiconductor, Inc.
|
||||
MI-0343 Micron Technology, Inc.
|
||||
OV7630 OmniVision Technologies, Inc.
|
||||
OV7660 OmniVision Technologies, Inc.
|
||||
PAS106B PixArt Imaging, Inc.
|
||||
PAS202BCA PixArt Imaging, Inc.
|
||||
PAS202BCB PixArt Imaging, Inc.
|
||||
TAS5110C1B Taiwan Advanced Sensor Corporation
|
||||
TAS5130D1B Taiwan Advanced Sensor Corporation
|
||||
Image sensor / SN9C1xx bridge | SN9C10[12] SN9C103 SN9C105 SN9C120
|
||||
-------------------------------------------------------------------------------
|
||||
HV7131D Hynix Semiconductor | Yes No No No
|
||||
HV7131R Hynix Semiconductor | No Yes Yes Yes
|
||||
MI-0343 Micron Technology | Yes No No No
|
||||
MI-0360 Micron Technology | No Yes No No
|
||||
OV7630 OmniVision Technologies | Yes Yes No No
|
||||
OV7660 OmniVision Technologies | No No Yes Yes
|
||||
PAS106B PixArt Imaging | Yes No No No
|
||||
PAS202B PixArt Imaging | Yes Yes No No
|
||||
TAS5110C1B Taiwan Advanced Sensor | Yes No No No
|
||||
TAS5110D Taiwan Advanced Sensor | Yes No No No
|
||||
TAS5130D1B Taiwan Advanced Sensor | Yes No No No
|
||||
|
||||
Some of the available control settings of each image sensor are supported
|
||||
"Yes" means that the pair is supported by the driver, while "No" means that the
|
||||
pair does not exist or is not supported by the driver.
|
||||
|
||||
Only some of the available control settings of each image sensor are supported
|
||||
through the V4L2 interface.
|
||||
|
||||
Donations of new models for further testing and support would be much
|
||||
|
@ -482,8 +493,8 @@ The SN9C1xx PC Camera Controllers can send images in two possible video
|
|||
formats over the USB: either native "Sequential RGB Bayer" or compressed.
|
||||
The compression is used to achieve high frame rates. With regard to the
|
||||
SN9C101, SN9C102 and SN9C103, the compression is based on the Huffman encoding
|
||||
algorithm described below, while the SN9C105 and SN9C120 the compression is
|
||||
based on the JPEG standard.
|
||||
algorithm described below, while with regard to the SN9C105 and SN9C120 the
|
||||
compression is based on the JPEG standard.
|
||||
The current video format may be selected or queried from the user application
|
||||
by calling the VIDIOC_S_FMT or VIDIOC_G_FMT ioctl's, as described in the V4L2
|
||||
API specifications.
|
||||
|
@ -573,4 +584,5 @@ order):
|
|||
- Mizuno Takafumi for the donation of a webcam;
|
||||
- an "anonymous" donator (who didn't want his name to be revealed) for the
|
||||
donation of a webcam.
|
||||
- an anonymous donator for the donation of four webcams.
|
||||
- an anonymous donator for the donation of four webcams and two boards with ten
|
||||
image sensors.
|
||||
|
|
|
@ -3606,7 +3606,7 @@ L: linux-usb-devel@lists.sourceforge.net
|
|||
W: http://www.connecttech.com
|
||||
S: Supported
|
||||
|
||||
USB SN9C10x DRIVER
|
||||
USB SN9C1xx DRIVER
|
||||
P: Luca Risolia
|
||||
M: luca.risolia@studio.unibo.it
|
||||
L: linux-usb-devel@lists.sourceforge.net
|
||||
|
|
|
@ -1,7 +1,14 @@
|
|||
sn9c102-objs := sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o \
|
||||
sn9c102_ov7630.o sn9c102_ov7660.o sn9c102_pas106b.o \
|
||||
sn9c102_pas202bcb.o sn9c102_tas5110c1b.o \
|
||||
sn9c102_tas5130d1b.o
|
||||
sn9c102-objs := sn9c102_core.o \
|
||||
sn9c102_hv7131d.o \
|
||||
sn9c102_hv7131r.o \
|
||||
sn9c102_mi0343.o \
|
||||
sn9c102_mi0360.o \
|
||||
sn9c102_ov7630.o \
|
||||
sn9c102_ov7660.o \
|
||||
sn9c102_pas106b.o \
|
||||
sn9c102_pas202bcb.o \
|
||||
sn9c102_tas5110c1b.o \
|
||||
sn9c102_tas5110d.o \
|
||||
sn9c102_tas5130d1b.o
|
||||
|
||||
obj-$(CONFIG_USB_SN9C102) += sn9c102.o
|
||||
|
||||
|
|
|
@ -78,8 +78,13 @@ enum sn9c102_stream_state {
|
|||
|
||||
typedef char sn9c102_sof_header_t[62];
|
||||
|
||||
struct sn9c102_sof_t {
|
||||
sn9c102_sof_header_t header;
|
||||
u16 bytesread;
|
||||
};
|
||||
|
||||
struct sn9c102_sysfs_attr {
|
||||
u8 reg, i2c_reg;
|
||||
u16 reg, i2c_reg;
|
||||
sn9c102_sof_header_t frame_header;
|
||||
};
|
||||
|
||||
|
@ -112,7 +117,7 @@ struct sn9c102_device {
|
|||
struct v4l2_jpegcompression compression;
|
||||
|
||||
struct sn9c102_sysfs_attr sysfs;
|
||||
sn9c102_sof_header_t sof_header;
|
||||
struct sn9c102_sof_t sof;
|
||||
u16 reg[384];
|
||||
|
||||
struct sn9c102_module_param module_param;
|
||||
|
@ -182,8 +187,8 @@ do { \
|
|||
if ((level) == 1 || (level) == 2) \
|
||||
pr_info("sn9c102: " fmt "\n", ## args); \
|
||||
else if ((level) == 3) \
|
||||
pr_debug("sn9c102: [%s:%d] " fmt "\n", __FUNCTION__, \
|
||||
__LINE__ , ## args); \
|
||||
pr_debug("sn9c102: [%s:%d] " fmt "\n", \
|
||||
__FUNCTION__, __LINE__ , ## args); \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
|
@ -194,8 +199,8 @@ do { \
|
|||
|
||||
#undef PDBG
|
||||
#define PDBG(fmt, args...) \
|
||||
dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \
|
||||
__FUNCTION__, __LINE__ , ## args)
|
||||
dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __FUNCTION__, \
|
||||
__LINE__ , ## args)
|
||||
|
||||
#undef PDBGG
|
||||
#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
|
||||
|
|
|
@ -44,11 +44,12 @@
|
|||
/*****************************************************************************/
|
||||
|
||||
#define SN9C102_MODULE_NAME "V4L2 driver for SN9C1xx PC Camera Controllers"
|
||||
#define SN9C102_MODULE_AUTHOR "(C) 2004-2006 Luca Risolia"
|
||||
#define SN9C102_MODULE_ALIAS "sn9c1xx"
|
||||
#define SN9C102_MODULE_AUTHOR "(C) 2004-2007 Luca Risolia"
|
||||
#define SN9C102_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
|
||||
#define SN9C102_MODULE_LICENSE "GPL"
|
||||
#define SN9C102_MODULE_VERSION "1:1.34"
|
||||
#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 34)
|
||||
#define SN9C102_MODULE_VERSION "1:1.39"
|
||||
#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 39)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
@ -56,6 +57,7 @@ MODULE_DEVICE_TABLE(usb, sn9c102_id_table);
|
|||
|
||||
MODULE_AUTHOR(SN9C102_MODULE_AUTHOR " " SN9C102_AUTHOR_EMAIL);
|
||||
MODULE_DESCRIPTION(SN9C102_MODULE_NAME);
|
||||
MODULE_ALIAS(SN9C102_MODULE_ALIAS);
|
||||
MODULE_VERSION(SN9C102_MODULE_VERSION);
|
||||
MODULE_LICENSE(SN9C102_MODULE_LICENSE);
|
||||
|
||||
|
@ -106,8 +108,7 @@ MODULE_PARM_DESC(debug,
|
|||
"\n1 = critical errors"
|
||||
"\n2 = significant informations"
|
||||
"\n3 = more verbose messages"
|
||||
"\nLevel 3 is useful for testing only, when only "
|
||||
"one device is used."
|
||||
"\nLevel 3 is useful for testing only."
|
||||
"\nDefault value is "__MODULE_STRING(SN9C102_DEBUG_LEVEL)"."
|
||||
"\n");
|
||||
#endif
|
||||
|
@ -121,8 +122,8 @@ sn9c102_request_buffers(struct sn9c102_device* cam, u32 count,
|
|||
struct v4l2_pix_format* p = &(cam->sensor.pix_format);
|
||||
struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
|
||||
size_t imagesize = cam->module_param.force_munmap || io == IO_READ ?
|
||||
(p->width * p->height * p->priv) / 8 :
|
||||
(r->width * r->height * p->priv) / 8;
|
||||
(p->width * p->height * p->priv) / 8 :
|
||||
(r->width * r->height * p->priv) / 8;
|
||||
void* buff = NULL;
|
||||
u32 i;
|
||||
|
||||
|
@ -485,18 +486,43 @@ static size_t sn9c102_sof_length(struct sn9c102_device* cam)
|
|||
static void*
|
||||
sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len)
|
||||
{
|
||||
char sof_header[6] = {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96};
|
||||
size_t soflen = 0, i;
|
||||
const char marker[6] = {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96};
|
||||
const char *m = mem;
|
||||
size_t soflen = 0, i, j;
|
||||
|
||||
soflen = sn9c102_sof_length(cam);
|
||||
|
||||
for (i = 0; (len >= soflen) && (i <= len - soflen); i++)
|
||||
if (!memcmp(mem + i, sof_header, sizeof(sof_header))) {
|
||||
memcpy(cam->sof_header, mem + i,
|
||||
sizeof(sn9c102_sof_header_t));
|
||||
/* Skip the header */
|
||||
return mem + i + soflen;
|
||||
for (i = 0; i < len; i++) {
|
||||
size_t b;
|
||||
|
||||
/* Read the variable part of the header */
|
||||
if (unlikely(cam->sof.bytesread >= sizeof(marker))) {
|
||||
cam->sof.header[cam->sof.bytesread] = *(m+i);
|
||||
if (++cam->sof.bytesread == soflen) {
|
||||
cam->sof.bytesread = 0;
|
||||
return mem + i;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Search for the SOF marker (fixed part) in the header */
|
||||
for (j = 0, b=cam->sof.bytesread; j+b < sizeof(marker); j++) {
|
||||
if (unlikely(i+j) == len)
|
||||
return NULL;
|
||||
if (*(m+i+j) == marker[cam->sof.bytesread]) {
|
||||
cam->sof.header[cam->sof.bytesread] = *(m+i+j);
|
||||
if (++cam->sof.bytesread == sizeof(marker)) {
|
||||
PDBGG("Bytes to analyze: %zd. SOF "
|
||||
"starts at byte #%zd", len, i);
|
||||
i += j+1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
cam->sof.bytesread = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -513,10 +539,16 @@ sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len)
|
|||
};
|
||||
size_t i, j;
|
||||
|
||||
/* The EOF header does not exist in compressed data */
|
||||
if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X ||
|
||||
cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_JPEG)
|
||||
return NULL; /* EOF header does not exist in compressed data */
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
The EOF header might cross the packet boundary, but this is not a
|
||||
problem, since the end of a frame is determined by checking its size
|
||||
in the first place.
|
||||
*/
|
||||
for (i = 0; (len >= 4) && (i <= len - 4); i++)
|
||||
for (j = 0; j < ARRAY_SIZE(eof_header); j++)
|
||||
if (!memcmp(mem + i, eof_header[j], 4))
|
||||
|
@ -639,6 +671,7 @@ static void sn9c102_urb_complete(struct urb *urb)
|
|||
cam->stream = STREAM_OFF;
|
||||
if ((*f))
|
||||
(*f)->state = F_QUEUED;
|
||||
cam->sof.bytesread = 0;
|
||||
DBG(3, "Stream interrupted by application");
|
||||
wake_up(&cam->wait_stream);
|
||||
}
|
||||
|
@ -676,6 +709,7 @@ static void sn9c102_urb_complete(struct urb *urb)
|
|||
if (status) {
|
||||
DBG(3, "Error in isochronous frame");
|
||||
(*f)->state = F_ERROR;
|
||||
cam->sof.bytesread = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -692,13 +726,13 @@ end_of_frame:
|
|||
if (eof)
|
||||
img = (eof > pos) ? eof - pos - 1 : 0;
|
||||
|
||||
if ((*f)->buf.bytesused+img > imagesize) {
|
||||
if ((*f)->buf.bytesused + img > imagesize) {
|
||||
u32 b;
|
||||
b = (*f)->buf.bytesused + img -
|
||||
imagesize;
|
||||
img = imagesize - (*f)->buf.bytesused;
|
||||
DBG(3, "Expected EOF not found: "
|
||||
"video frame cut");
|
||||
PDBGG("Expected EOF not found: video "
|
||||
"frame cut");
|
||||
if (eof)
|
||||
DBG(3, "Exceeded limit: +%u "
|
||||
"bytes", (unsigned)(b));
|
||||
|
@ -719,11 +753,6 @@ end_of_frame:
|
|||
V4L2_PIX_FMT_JPEG) && eof)) {
|
||||
u32 b;
|
||||
|
||||
if (cam->sensor.pix_format.pixelformat
|
||||
== V4L2_PIX_FMT_JPEG)
|
||||
sn9c102_write_eoimarker(cam,
|
||||
(*f));
|
||||
|
||||
b = (*f)->buf.bytesused;
|
||||
(*f)->state = F_DONE;
|
||||
(*f)->buf.sequence= ++cam->frame_count;
|
||||
|
@ -741,7 +770,7 @@ end_of_frame:
|
|||
spin_unlock(&cam->queue_lock);
|
||||
|
||||
memcpy(cam->sysfs.frame_header,
|
||||
cam->sof_header, soflen);
|
||||
cam->sof.header, soflen);
|
||||
|
||||
DBG(3, "Video frame captured: %lu "
|
||||
"bytes", (unsigned long)(b));
|
||||
|
@ -791,7 +820,13 @@ start_of_frame:
|
|||
V4L2_PIX_FMT_SN9C10X ||
|
||||
cam->sensor.pix_format.pixelformat ==
|
||||
V4L2_PIX_FMT_JPEG) {
|
||||
eof = sof - soflen;
|
||||
if (sof - pos >= soflen) {
|
||||
eof = sof - soflen;
|
||||
} else { /* remove header */
|
||||
eof = pos;
|
||||
(*f)->buf.bytesused -=
|
||||
(soflen - (sof - pos));
|
||||
}
|
||||
goto end_of_frame;
|
||||
} else {
|
||||
DBG(3, "SOF before expected EOF after "
|
||||
|
@ -878,6 +913,7 @@ static int sn9c102_start_transfer(struct sn9c102_device* cam)
|
|||
}
|
||||
|
||||
cam->frame_current = NULL;
|
||||
cam->sof.bytesread = 0;
|
||||
|
||||
for (i = 0; i < SN9C102_URBS; i++) {
|
||||
err = usb_submit_urb(cam->urb[i], GFP_KERNEL);
|
||||
|
@ -959,9 +995,9 @@ static u16 sn9c102_strtou16(const char* buff, size_t len, ssize_t* count)
|
|||
|
||||
if (len < 6) {
|
||||
strncpy(str, buff, len);
|
||||
str[len+1] = '\0';
|
||||
str[len] = '\0';
|
||||
} else {
|
||||
strncpy(str, buff, 4);
|
||||
strncpy(str, buff, 6);
|
||||
str[6] = '\0';
|
||||
}
|
||||
|
||||
|
@ -1062,7 +1098,7 @@ static ssize_t sn9c102_show_val(struct class_device* cd, char* buf)
|
|||
|
||||
count = sprintf(buf, "%d\n", val);
|
||||
|
||||
DBG(3, "Read bytes: %zd", count);
|
||||
DBG(3, "Read bytes: %zd, value: %d", count, val);
|
||||
|
||||
mutex_unlock(&sn9c102_sysfs_lock);
|
||||
|
||||
|
@ -1197,7 +1233,7 @@ static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf)
|
|||
|
||||
count = sprintf(buf, "%d\n", val);
|
||||
|
||||
DBG(3, "Read bytes: %zd", count);
|
||||
DBG(3, "Read bytes: %zd, value: %d", count, val);
|
||||
|
||||
mutex_unlock(&sn9c102_sysfs_lock);
|
||||
|
||||
|
@ -1477,10 +1513,10 @@ sn9c102_set_compression(struct sn9c102_device* cam,
|
|||
case BRIDGE_SN9C101:
|
||||
case BRIDGE_SN9C102:
|
||||
case BRIDGE_SN9C103:
|
||||
if (compression->quality == 0)
|
||||
if (compression->quality == 0)
|
||||
err += sn9c102_write_reg(cam, cam->reg[0x17] | 0x01,
|
||||
0x17);
|
||||
else if (compression->quality == 1)
|
||||
else if (compression->quality == 1)
|
||||
err += sn9c102_write_reg(cam, cam->reg[0x17] & 0xfe,
|
||||
0x17);
|
||||
break;
|
||||
|
@ -1489,10 +1525,10 @@ sn9c102_set_compression(struct sn9c102_device* cam,
|
|||
if (compression->quality == 0) {
|
||||
for (i = 0; i <= 63; i++) {
|
||||
err += sn9c102_write_reg(cam,
|
||||
SN9C102_Y_QTABLE0[i],
|
||||
SN9C102_Y_QTABLE1[i],
|
||||
0x100 + i);
|
||||
err += sn9c102_write_reg(cam,
|
||||
SN9C102_UV_QTABLE0[i],
|
||||
SN9C102_UV_QTABLE1[i],
|
||||
0x140 + i);
|
||||
}
|
||||
err += sn9c102_write_reg(cam, cam->reg[0x18] & 0xbf,
|
||||
|
@ -1597,9 +1633,13 @@ static int sn9c102_init(struct sn9c102_device* cam)
|
|||
if (cam->bridge == BRIDGE_SN9C101 ||
|
||||
cam->bridge == BRIDGE_SN9C102 ||
|
||||
cam->bridge == BRIDGE_SN9C103) {
|
||||
if (s->pix_format.pixelformat == V4L2_PIX_FMT_JPEG)
|
||||
s->pix_format.pixelformat= V4L2_PIX_FMT_SBGGR8;
|
||||
cam->compression.quality = cam->reg[0x17] & 0x01 ?
|
||||
0 : 1;
|
||||
} else {
|
||||
if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
|
||||
s->pix_format.pixelformat = V4L2_PIX_FMT_JPEG;
|
||||
cam->compression.quality = cam->reg[0x18] & 0x40 ?
|
||||
0 : 1;
|
||||
err += sn9c102_set_compression(cam, &cam->compression);
|
||||
|
@ -1805,7 +1845,7 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
|
|||
DBG(3, "Close and open the device again to choose "
|
||||
"the read method");
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return -EINVAL;
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (cam->io == IO_NONE) {
|
||||
|
@ -1845,16 +1885,16 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
|
|||
return err;
|
||||
}
|
||||
} else {
|
||||
timeout = wait_event_interruptible_timeout
|
||||
( cam->wait_frame,
|
||||
(!list_empty(&cam->outqueue)) ||
|
||||
(cam->state & DEV_DISCONNECTED) ||
|
||||
(cam->state & DEV_MISCONFIGURED),
|
||||
cam->module_param.frame_timeout *
|
||||
1000 * msecs_to_jiffies(1) );
|
||||
if (timeout < 0) {
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return timeout;
|
||||
timeout = wait_event_interruptible_timeout
|
||||
( cam->wait_frame,
|
||||
(!list_empty(&cam->outqueue)) ||
|
||||
(cam->state & DEV_DISCONNECTED) ||
|
||||
(cam->state & DEV_MISCONFIGURED),
|
||||
cam->module_param.frame_timeout *
|
||||
1000 * msecs_to_jiffies(1) );
|
||||
if (timeout < 0) {
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return timeout;
|
||||
} else if (timeout == 0 &&
|
||||
!(cam->state & DEV_DISCONNECTED)) {
|
||||
DBG(1, "Video frame timeout elapsed");
|
||||
|
@ -2001,7 +2041,12 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
|
||||
if (!(vma->vm_flags & (VM_WRITE | VM_READ))) {
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
if (cam->io != IO_MMAP ||
|
||||
size != PAGE_ALIGN(cam->frame[0].buf.length)) {
|
||||
mutex_unlock(&cam->fileop_mutex);
|
||||
return -EINVAL;
|
||||
|
@ -2267,7 +2312,7 @@ sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg)
|
|||
if (cam->frame[i].vma_use_count) {
|
||||
DBG(3, "VIDIOC_S_CROP failed. "
|
||||
"Unmap the buffers first.");
|
||||
return -EINVAL;
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* Preserve R,G or B origin */
|
||||
|
@ -2410,8 +2455,8 @@ sn9c102_vidioc_enum_fmt(struct sn9c102_device* cam, void __user * arg)
|
|||
case BRIDGE_SN9C101:
|
||||
case BRIDGE_SN9C102:
|
||||
case BRIDGE_SN9C103:
|
||||
strcpy(fmtd.description, "compressed");
|
||||
fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X;
|
||||
strcpy(fmtd.description, "compressed");
|
||||
fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X;
|
||||
break;
|
||||
case BRIDGE_SN9C105:
|
||||
case BRIDGE_SN9C120:
|
||||
|
@ -2445,8 +2490,10 @@ sn9c102_vidioc_g_fmt(struct sn9c102_device* cam, void __user * arg)
|
|||
if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||
return -EINVAL;
|
||||
|
||||
pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_SN9C10X ||
|
||||
pfmt->pixelformat==V4L2_PIX_FMT_JPEG)
|
||||
pfmt->colorspace = (pfmt->pixelformat == V4L2_PIX_FMT_JPEG) ?
|
||||
V4L2_COLORSPACE_JPEG : V4L2_COLORSPACE_SRGB;
|
||||
pfmt->bytesperline = (pfmt->pixelformat == V4L2_PIX_FMT_SN9C10X ||
|
||||
pfmt->pixelformat == V4L2_PIX_FMT_JPEG)
|
||||
? 0 : (pfmt->width * pfmt->priv) / 8;
|
||||
pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
|
||||
pfmt->field = V4L2_FIELD_NONE;
|
||||
|
@ -2521,9 +2568,9 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd,
|
|||
case BRIDGE_SN9C101:
|
||||
case BRIDGE_SN9C102:
|
||||
case BRIDGE_SN9C103:
|
||||
if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X &&
|
||||
pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
|
||||
pix->pixelformat = pfmt->pixelformat;
|
||||
if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X &&
|
||||
pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
|
||||
pix->pixelformat = pfmt->pixelformat;
|
||||
break;
|
||||
case BRIDGE_SN9C105:
|
||||
case BRIDGE_SN9C120:
|
||||
|
@ -2533,7 +2580,8 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd,
|
|||
break;
|
||||
}
|
||||
pix->priv = pfmt->priv; /* bpp */
|
||||
pix->colorspace = pfmt->colorspace;
|
||||
pix->colorspace = (pix->pixelformat == V4L2_PIX_FMT_JPEG) ?
|
||||
V4L2_COLORSPACE_JPEG : V4L2_COLORSPACE_SRGB;
|
||||
pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X ||
|
||||
pix->pixelformat == V4L2_PIX_FMT_JPEG)
|
||||
? 0 : (pix->width * pix->priv) / 8;
|
||||
|
@ -2551,7 +2599,7 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd,
|
|||
if (cam->frame[i].vma_use_count) {
|
||||
DBG(3, "VIDIOC_S_FMT failed. Unmap the "
|
||||
"buffers first.");
|
||||
return -EINVAL;
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (cam->stream == STREAM_ON)
|
||||
|
@ -2666,14 +2714,14 @@ sn9c102_vidioc_reqbufs(struct sn9c102_device* cam, void __user * arg)
|
|||
if (cam->io == IO_READ) {
|
||||
DBG(3, "Close and open the device again to choose the mmap "
|
||||
"I/O method");
|
||||
return -EINVAL;
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
for (i = 0; i < cam->nbuffers; i++)
|
||||
if (cam->frame[i].vma_use_count) {
|
||||
DBG(3, "VIDIOC_REQBUFS failed. Previous buffers are "
|
||||
"still mapped.");
|
||||
return -EINVAL;
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (cam->stream == STREAM_ON)
|
||||
|
@ -2785,15 +2833,15 @@ sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp,
|
|||
if (err)
|
||||
return err;
|
||||
} else {
|
||||
timeout = wait_event_interruptible_timeout
|
||||
( cam->wait_frame,
|
||||
(!list_empty(&cam->outqueue)) ||
|
||||
(cam->state & DEV_DISCONNECTED) ||
|
||||
(cam->state & DEV_MISCONFIGURED),
|
||||
cam->module_param.frame_timeout *
|
||||
1000 * msecs_to_jiffies(1) );
|
||||
if (timeout < 0)
|
||||
return timeout;
|
||||
timeout = wait_event_interruptible_timeout
|
||||
( cam->wait_frame,
|
||||
(!list_empty(&cam->outqueue)) ||
|
||||
(cam->state & DEV_DISCONNECTED) ||
|
||||
(cam->state & DEV_MISCONFIGURED),
|
||||
cam->module_param.frame_timeout *
|
||||
1000 * msecs_to_jiffies(1) );
|
||||
if (timeout < 0)
|
||||
return timeout;
|
||||
else if (timeout == 0 &&
|
||||
!(cam->state & DEV_DISCONNECTED)) {
|
||||
DBG(1, "Video frame timeout elapsed");
|
||||
|
@ -2837,9 +2885,6 @@ sn9c102_vidioc_streamon(struct sn9c102_device* cam, void __user * arg)
|
|||
if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
|
||||
return -EINVAL;
|
||||
|
||||
if (list_empty(&cam->inqueue))
|
||||
return -EINVAL;
|
||||
|
||||
cam->stream = STREAM_ON;
|
||||
|
||||
DBG(3, "Stream on");
|
||||
|
@ -3166,8 +3211,8 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
|
|||
|
||||
r = sn9c102_read_reg(cam, 0x00);
|
||||
if (r < 0 || (r != 0x10 && r != 0x11 && r != 0x12)) {
|
||||
DBG(1, "Sorry, this is not a SN9C1xx based camera "
|
||||
"(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
|
||||
DBG(1, "Sorry, this is not a SN9C1xx-based camera "
|
||||
"(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
|
||||
err = -ENODEV;
|
||||
goto fail;
|
||||
}
|
||||
|
@ -3177,19 +3222,19 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
|
|||
case BRIDGE_SN9C101:
|
||||
case BRIDGE_SN9C102:
|
||||
DBG(2, "SN9C10[12] PC Camera Controller detected "
|
||||
"(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
|
||||
"(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
|
||||
break;
|
||||
case BRIDGE_SN9C103:
|
||||
DBG(2, "SN9C103 PC Camera Controller detected "
|
||||
"(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
|
||||
"(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
|
||||
break;
|
||||
case BRIDGE_SN9C105:
|
||||
DBG(2, "SN9C105 PC Camera Controller detected "
|
||||
"(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
|
||||
"(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
|
||||
break;
|
||||
case BRIDGE_SN9C120:
|
||||
DBG(2, "SN9C120 PC Camera Controller detected "
|
||||
"(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
|
||||
"(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -3260,6 +3305,8 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
|
|||
"device controlling. Error #%d", err);
|
||||
#else
|
||||
DBG(2, "Optional device control through 'sysfs' interface disabled");
|
||||
DBG(3, "Compile the kernel with the 'CONFIG_VIDEO_ADV_DEBUG' "
|
||||
"configuration option to enable it.");
|
||||
#endif
|
||||
|
||||
usb_set_intfdata(intf, cam);
|
||||
|
|
|
@ -89,16 +89,22 @@ static const struct usb_device_id sn9c102_id_table[] = {
|
|||
{ 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, 0x60c2, 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, 0x60ef, 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, 0x6102, BRIDGE_SN9C120), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x6108, BRIDGE_SN9C120), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x610f, BRIDGE_SN9C120), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x6130, BRIDGE_SN9C120), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x6138, BRIDGE_SN9C120), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x613a, BRIDGE_SN9C120), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), },
|
||||
{ SN9C102_USB_DEVICE(0x0c45, 0x613c, BRIDGE_SN9C120), },
|
||||
|
@ -114,12 +120,15 @@ static const struct usb_device_id sn9c102_id_table[] = {
|
|||
Functions must return 0 on success, the appropriate error otherwise.
|
||||
*/
|
||||
extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam);
|
||||
extern int sn9c102_probe_hv7131r(struct sn9c102_device* cam);
|
||||
extern int sn9c102_probe_mi0343(struct sn9c102_device* cam);
|
||||
extern int sn9c102_probe_mi0360(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_tas5110d(struct sn9c102_device* cam);
|
||||
extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam);
|
||||
|
||||
/*
|
||||
|
@ -128,13 +137,16 @@ extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam);
|
|||
the order of the list below, from top to bottom.
|
||||
*/
|
||||
static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = {
|
||||
&sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */
|
||||
&sn9c102_probe_hv7131r, /* strong detection based on SENSOR ids */
|
||||
&sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */
|
||||
&sn9c102_probe_mi0360, /* 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_tas5110d, /* detection based on USB pid/vid */
|
||||
&sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */
|
||||
NULL,
|
||||
};
|
||||
|
|
|
@ -22,9 +22,6 @@
|
|||
#include "sn9c102_sensor.h"
|
||||
|
||||
|
||||
static struct sn9c102_sensor hv7131d;
|
||||
|
||||
|
||||
static int hv7131d_init(struct sn9c102_device* cam)
|
||||
{
|
||||
int err = 0;
|
||||
|
@ -153,7 +150,7 @@ static int hv7131d_set_pix_format(struct sn9c102_device* cam,
|
|||
static struct sn9c102_sensor hv7131d = {
|
||||
.name = "HV7131D",
|
||||
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
|
||||
.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
|
||||
.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102,
|
||||
.sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
|
||||
.frequency = SN9C102_I2C_100KHZ,
|
||||
.interface = SN9C102_I2C_2WIRES,
|
||||
|
@ -263,7 +260,7 @@ int sn9c102_probe_hv7131d(struct sn9c102_device* cam)
|
|||
if (r0 < 0 || r1 < 0)
|
||||
return -EIO;
|
||||
|
||||
if (r0 != 0x00 && r1 != 0x04)
|
||||
if (r0 != 0x00 || r1 != 0x04)
|
||||
return -ENODEV;
|
||||
|
||||
sn9c102_attach_sensor(cam, &hv7131d);
|
||||
|
|
|
@ -0,0 +1,458 @@
|
|||
/***************************************************************************
|
||||
* Plug-in for HV7131R 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 int hv7131r_init(struct sn9c102_device* cam)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
switch (sn9c102_get_bridge(cam)) {
|
||||
case BRIDGE_SN9C103:
|
||||
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, 0x03, 0x10);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x14);
|
||||
err += sn9c102_write_reg(cam, 0x60, 0x17);
|
||||
err += sn9c102_write_reg(cam, 0x0a, 0x18);
|
||||
err += sn9c102_write_reg(cam, 0xf0, 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);
|
||||
break;
|
||||
case BRIDGE_SN9C105:
|
||||
case BRIDGE_SN9C120:
|
||||
err += sn9c102_write_reg(cam, 0x44, 0x01);
|
||||
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, 0x44, 0x05);
|
||||
err += sn9c102_write_reg(cam, 0x3e, 0x06);
|
||||
err += sn9c102_write_reg(cam, 0x1a, 0x07);
|
||||
err += sn9c102_write_reg(cam, 0x03, 0x10);
|
||||
err += sn9c102_write_reg(cam, 0x08, 0x14);
|
||||
err += sn9c102_write_reg(cam, 0xa3, 0x17);
|
||||
err += sn9c102_write_reg(cam, 0x4b, 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);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
err += sn9c102_i2c_write(cam, 0x20, 0x00);
|
||||
err += sn9c102_i2c_write(cam, 0x21, 0xd6);
|
||||
err += sn9c102_i2c_write(cam, 0x25, 0x06);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static int hv7131r_get_ctrl(struct sn9c102_device* cam,
|
||||
struct v4l2_control* ctrl)
|
||||
{
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_GAIN:
|
||||
if ((ctrl->value = sn9c102_i2c_read(cam, 0x30)) < 0)
|
||||
return -EIO;
|
||||
return 0;
|
||||
case V4L2_CID_RED_BALANCE:
|
||||
if ((ctrl->value = sn9c102_i2c_read(cam, 0x31)) < 0)
|
||||
return -EIO;
|
||||
ctrl->value = ctrl->value & 0x3f;
|
||||
return 0;
|
||||
case V4L2_CID_BLUE_BALANCE:
|
||||
if ((ctrl->value = sn9c102_i2c_read(cam, 0x33)) < 0)
|
||||
return -EIO;
|
||||
ctrl->value = ctrl->value & 0x3f;
|
||||
return 0;
|
||||
case SN9C102_V4L2_CID_GREEN_BALANCE:
|
||||
if ((ctrl->value = sn9c102_i2c_read(cam, 0x32)) < 0)
|
||||
return -EIO;
|
||||
ctrl->value = ctrl->value & 0x3f;
|
||||
return 0;
|
||||
case V4L2_CID_BLACK_LEVEL:
|
||||
if ((ctrl->value = sn9c102_i2c_read(cam, 0x01)) < 0)
|
||||
return -EIO;
|
||||
ctrl->value = (ctrl->value & 0x08) ? 1 : 0;
|
||||
return 0;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int hv7131r_set_ctrl(struct sn9c102_device* cam,
|
||||
const struct v4l2_control* ctrl)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_GAIN:
|
||||
err += sn9c102_i2c_write(cam, 0x30, ctrl->value);
|
||||
break;
|
||||
case V4L2_CID_RED_BALANCE:
|
||||
err += sn9c102_i2c_write(cam, 0x31, ctrl->value);
|
||||
break;
|
||||
case V4L2_CID_BLUE_BALANCE:
|
||||
err += sn9c102_i2c_write(cam, 0x33, ctrl->value);
|
||||
break;
|
||||
case SN9C102_V4L2_CID_GREEN_BALANCE:
|
||||
err += sn9c102_i2c_write(cam, 0x32, ctrl->value);
|
||||
break;
|
||||
case V4L2_CID_BLACK_LEVEL:
|
||||
{
|
||||
int r = sn9c102_i2c_read(cam, 0x01);
|
||||
if (r < 0)
|
||||
return -EIO;
|
||||
err += sn9c102_i2c_write(cam, 0x01,
|
||||
(ctrl->value<<3) | (r&0xf7));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return err ? -EIO : 0;
|
||||
}
|
||||
|
||||
|
||||
static int hv7131r_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 hv7131r_set_pix_format(struct sn9c102_device* cam,
|
||||
const struct v4l2_pix_format* pix)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
switch (sn9c102_get_bridge(cam)) {
|
||||
case BRIDGE_SN9C103:
|
||||
if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) {
|
||||
err += sn9c102_write_reg(cam, 0xa0, 0x19);
|
||||
err += sn9c102_i2c_write(cam, 0x01, 0x04);
|
||||
} else {
|
||||
err += sn9c102_write_reg(cam, 0x30, 0x19);
|
||||
err += sn9c102_i2c_write(cam, 0x01, 0x04);
|
||||
}
|
||||
break;
|
||||
case BRIDGE_SN9C105:
|
||||
case BRIDGE_SN9C120:
|
||||
if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) {
|
||||
err += sn9c102_write_reg(cam, 0xa5, 0x17);
|
||||
err += sn9c102_i2c_write(cam, 0x01, 0x24);
|
||||
} else {
|
||||
err += sn9c102_write_reg(cam, 0xa3, 0x17);
|
||||
err += sn9c102_i2c_write(cam, 0x01, 0x04);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static struct sn9c102_sensor hv7131r = {
|
||||
.name = "HV7131R",
|
||||
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
|
||||
.supported_bridge = BRIDGE_SN9C103 | BRIDGE_SN9C105 | BRIDGE_SN9C120,
|
||||
.sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
|
||||
.frequency = SN9C102_I2C_100KHZ,
|
||||
.interface = SN9C102_I2C_2WIRES,
|
||||
.i2c_slave_id = 0x11,
|
||||
.init = &hv7131r_init,
|
||||
.qctrl = {
|
||||
{
|
||||
.id = V4L2_CID_GAIN,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "global gain",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0xff,
|
||||
.step = 0x01,
|
||||
.default_value = 0x40,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_RED_BALANCE,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "red balance",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0x3f,
|
||||
.step = 0x01,
|
||||
.default_value = 0x08,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_BLUE_BALANCE,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "blue balance",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0x3f,
|
||||
.step = 0x01,
|
||||
.default_value = 0x1a,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = SN9C102_V4L2_CID_GREEN_BALANCE,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "green balance",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0x3f,
|
||||
.step = 0x01,
|
||||
.default_value = 0x2f,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_BLACK_LEVEL,
|
||||
.type = V4L2_CTRL_TYPE_BOOLEAN,
|
||||
.name = "auto black level compensation",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0x01,
|
||||
.step = 0x01,
|
||||
.default_value = 0x00,
|
||||
.flags = 0,
|
||||
},
|
||||
},
|
||||
.get_ctrl = &hv7131r_get_ctrl,
|
||||
.set_ctrl = &hv7131r_set_ctrl,
|
||||
.cropcap = {
|
||||
.bounds = {
|
||||
.left = 0,
|
||||
.top = 0,
|
||||
.width = 640,
|
||||
.height = 480,
|
||||
},
|
||||
.defrect = {
|
||||
.left = 0,
|
||||
.top = 0,
|
||||
.width = 640,
|
||||
.height = 480,
|
||||
},
|
||||
},
|
||||
.set_crop = &hv7131r_set_crop,
|
||||
.pix_format = {
|
||||
.width = 640,
|
||||
.height = 480,
|
||||
.pixelformat = V4L2_PIX_FMT_SBGGR8,
|
||||
.priv = 8,
|
||||
},
|
||||
.set_pix_format = &hv7131r_set_pix_format
|
||||
};
|
||||
|
||||
|
||||
int sn9c102_probe_hv7131r(struct sn9c102_device* cam)
|
||||
{
|
||||
int devid, err = 0;
|
||||
|
||||
err += sn9c102_write_reg(cam, 0x09, 0x01);
|
||||
err += sn9c102_write_reg(cam, 0x44, 0x02);
|
||||
err += sn9c102_write_reg(cam, 0x34, 0x01);
|
||||
err += sn9c102_write_reg(cam, 0x20, 0x17);
|
||||
err += sn9c102_write_reg(cam, 0x34, 0x01);
|
||||
err += sn9c102_write_reg(cam, 0x46, 0x01);
|
||||
if (err)
|
||||
return -EIO;
|
||||
|
||||
devid = sn9c102_i2c_try_read(cam, &hv7131r, 0x00);
|
||||
if (devid < 0)
|
||||
return -EIO;
|
||||
|
||||
if (devid != 0x02)
|
||||
return -ENODEV;
|
||||
|
||||
sn9c102_attach_sensor(cam, &hv7131r);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -22,12 +22,9 @@
|
|||
#include "sn9c102_sensor.h"
|
||||
|
||||
|
||||
static struct sn9c102_sensor mi0343;
|
||||
static u8 mi0343_i2c_data[5+1];
|
||||
|
||||
|
||||
static int mi0343_init(struct sn9c102_device* cam)
|
||||
{
|
||||
struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
|
||||
int err = 0;
|
||||
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x10);
|
||||
|
@ -38,20 +35,20 @@ static int mi0343_init(struct sn9c102_device* cam)
|
|||
err += sn9c102_write_reg(cam, 0x07, 0x18);
|
||||
err += sn9c102_write_reg(cam, 0xa0, 0x19);
|
||||
|
||||
err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
|
||||
0x0d, 0x00, 0x01, 0, 0);
|
||||
err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
|
||||
0x0d, 0x00, 0x00, 0, 0);
|
||||
err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
|
||||
0x03, 0x01, 0xe1, 0, 0);
|
||||
err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
|
||||
0x04, 0x02, 0x81, 0, 0);
|
||||
err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
|
||||
0x05, 0x00, 0x17, 0, 0);
|
||||
err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
|
||||
0x06, 0x00, 0x11, 0, 0);
|
||||
err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id,
|
||||
0x62, 0x04, 0x9a, 0, 0);
|
||||
err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d,
|
||||
0x00, 0x01, 0, 0);
|
||||
err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d,
|
||||
0x00, 0x00, 0, 0);
|
||||
err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03,
|
||||
0x01, 0xe1, 0, 0);
|
||||
err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04,
|
||||
0x02, 0x81, 0, 0);
|
||||
err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05,
|
||||
0x00, 0x17, 0, 0);
|
||||
err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06,
|
||||
0x00, 0x11, 0, 0);
|
||||
err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x62,
|
||||
0x04, 0x9a, 0, 0);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -60,43 +57,46 @@ static int mi0343_init(struct sn9c102_device* cam)
|
|||
static int mi0343_get_ctrl(struct sn9c102_device* cam,
|
||||
struct v4l2_control* ctrl)
|
||||
{
|
||||
struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
|
||||
u8 data[5+1];
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_EXPOSURE:
|
||||
if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
|
||||
0x09, 2+1, mi0343_i2c_data) < 0)
|
||||
if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x09,
|
||||
2+1, data) < 0)
|
||||
return -EIO;
|
||||
ctrl->value = mi0343_i2c_data[2];
|
||||
ctrl->value = data[2];
|
||||
return 0;
|
||||
case V4L2_CID_GAIN:
|
||||
if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
|
||||
0x35, 2+1, mi0343_i2c_data) < 0)
|
||||
if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x35,
|
||||
2+1, data) < 0)
|
||||
return -EIO;
|
||||
break;
|
||||
case V4L2_CID_HFLIP:
|
||||
if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
|
||||
0x20, 2+1, mi0343_i2c_data) < 0)
|
||||
if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20,
|
||||
2+1, data) < 0)
|
||||
return -EIO;
|
||||
ctrl->value = mi0343_i2c_data[3] & 0x20 ? 1 : 0;
|
||||
ctrl->value = data[3] & 0x20 ? 1 : 0;
|
||||
return 0;
|
||||
case V4L2_CID_VFLIP:
|
||||
if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
|
||||
0x20, 2+1, mi0343_i2c_data) < 0)
|
||||
if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20,
|
||||
2+1, data) < 0)
|
||||
return -EIO;
|
||||
ctrl->value = mi0343_i2c_data[3] & 0x80 ? 1 : 0;
|
||||
ctrl->value = data[3] & 0x80 ? 1 : 0;
|
||||
return 0;
|
||||
case V4L2_CID_RED_BALANCE:
|
||||
if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
|
||||
0x2d, 2+1, mi0343_i2c_data) < 0)
|
||||
if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2d,
|
||||
2+1, data) < 0)
|
||||
return -EIO;
|
||||
break;
|
||||
case V4L2_CID_BLUE_BALANCE:
|
||||
if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
|
||||
0x2c, 2+1, mi0343_i2c_data) < 0)
|
||||
if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2c,
|
||||
2+1, data) < 0)
|
||||
return -EIO;
|
||||
break;
|
||||
case SN9C102_V4L2_CID_GREEN_BALANCE:
|
||||
if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id,
|
||||
0x2e, 2+1, mi0343_i2c_data) < 0)
|
||||
if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2e,
|
||||
2+1, data) < 0)
|
||||
return -EIO;
|
||||
break;
|
||||
default:
|
||||
|
@ -108,7 +108,7 @@ static int mi0343_get_ctrl(struct sn9c102_device* cam,
|
|||
case V4L2_CID_RED_BALANCE:
|
||||
case V4L2_CID_BLUE_BALANCE:
|
||||
case SN9C102_V4L2_CID_GREEN_BALANCE:
|
||||
ctrl->value = mi0343_i2c_data[3] | (mi0343_i2c_data[2] << 8);
|
||||
ctrl->value = data[3] | (data[2] << 8);
|
||||
if (ctrl->value >= 0x10 && ctrl->value <= 0x3f)
|
||||
ctrl->value -= 0x10;
|
||||
else if (ctrl->value >= 0x60 && ctrl->value <= 0x7f)
|
||||
|
@ -124,6 +124,7 @@ static int mi0343_get_ctrl(struct sn9c102_device* cam,
|
|||
static int mi0343_set_ctrl(struct sn9c102_device* cam,
|
||||
const struct v4l2_control* ctrl)
|
||||
{
|
||||
struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
|
||||
u16 reg = 0;
|
||||
int err = 0;
|
||||
|
||||
|
@ -143,50 +144,42 @@ static int mi0343_set_ctrl(struct sn9c102_device* cam,
|
|||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_EXPOSURE:
|
||||
err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
|
||||
mi0343.i2c_slave_id,
|
||||
err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
|
||||
0x09, ctrl->value, 0x00,
|
||||
0, 0);
|
||||
break;
|
||||
case V4L2_CID_GAIN:
|
||||
err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
|
||||
mi0343.i2c_slave_id,
|
||||
err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
|
||||
0x35, reg >> 8, reg & 0xff,
|
||||
0, 0);
|
||||
break;
|
||||
case V4L2_CID_HFLIP:
|
||||
err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
|
||||
mi0343.i2c_slave_id,
|
||||
err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
|
||||
0x20, ctrl->value ? 0x40:0x00,
|
||||
ctrl->value ? 0x20:0x00,
|
||||
0, 0);
|
||||
break;
|
||||
case V4L2_CID_VFLIP:
|
||||
err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
|
||||
mi0343.i2c_slave_id,
|
||||
err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
|
||||
0x20, ctrl->value ? 0x80:0x00,
|
||||
ctrl->value ? 0x80:0x00,
|
||||
0, 0);
|
||||
break;
|
||||
case V4L2_CID_RED_BALANCE:
|
||||
err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
|
||||
mi0343.i2c_slave_id,
|
||||
err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
|
||||
0x2d, reg >> 8, reg & 0xff,
|
||||
0, 0);
|
||||
break;
|
||||
case V4L2_CID_BLUE_BALANCE:
|
||||
err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
|
||||
mi0343.i2c_slave_id,
|
||||
err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
|
||||
0x2c, reg >> 8, reg & 0xff,
|
||||
0, 0);
|
||||
break;
|
||||
case SN9C102_V4L2_CID_GREEN_BALANCE:
|
||||
err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
|
||||
mi0343.i2c_slave_id,
|
||||
err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
|
||||
0x2b, reg >> 8, reg & 0xff,
|
||||
0, 0);
|
||||
err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
|
||||
mi0343.i2c_slave_id,
|
||||
err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
|
||||
0x2e, reg >> 8, reg & 0xff,
|
||||
0, 0);
|
||||
break;
|
||||
|
@ -216,16 +209,15 @@ static int mi0343_set_crop(struct sn9c102_device* cam,
|
|||
static int mi0343_set_pix_format(struct sn9c102_device* cam,
|
||||
const struct v4l2_pix_format* pix)
|
||||
{
|
||||
struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
|
||||
int err = 0;
|
||||
|
||||
if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) {
|
||||
err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
|
||||
mi0343.i2c_slave_id,
|
||||
err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
|
||||
0x0a, 0x00, 0x03, 0, 0);
|
||||
err += sn9c102_write_reg(cam, 0x20, 0x19);
|
||||
} else {
|
||||
err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4,
|
||||
mi0343.i2c_slave_id,
|
||||
err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
|
||||
0x0a, 0x00, 0x05, 0, 0);
|
||||
err += sn9c102_write_reg(cam, 0xa0, 0x19);
|
||||
}
|
||||
|
@ -237,7 +229,7 @@ static int mi0343_set_pix_format(struct sn9c102_device* cam,
|
|||
static struct sn9c102_sensor mi0343 = {
|
||||
.name = "MI-0343",
|
||||
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
|
||||
.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
|
||||
.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102,
|
||||
.frequency = SN9C102_I2C_100KHZ,
|
||||
.interface = SN9C102_I2C_2WIRES,
|
||||
.i2c_slave_id = 0x5d,
|
||||
|
@ -343,6 +335,7 @@ static struct sn9c102_sensor mi0343 = {
|
|||
|
||||
int sn9c102_probe_mi0343(struct sn9c102_device* cam)
|
||||
{
|
||||
u8 data[5+1];
|
||||
int err = 0;
|
||||
|
||||
err += sn9c102_write_reg(cam, 0x01, 0x01);
|
||||
|
@ -352,10 +345,10 @@ int sn9c102_probe_mi0343(struct sn9c102_device* cam)
|
|||
return -EIO;
|
||||
|
||||
if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, 0x00,
|
||||
2, mi0343_i2c_data) < 0)
|
||||
2, data) < 0)
|
||||
return -EIO;
|
||||
|
||||
if (mi0343_i2c_data[4] != 0x32 && mi0343_i2c_data[3] != 0xe3)
|
||||
if (data[4] != 0x32 || data[3] != 0xe3)
|
||||
return -ENODEV;
|
||||
|
||||
sn9c102_attach_sensor(cam, &mi0343);
|
||||
|
|
|
@ -0,0 +1,353 @@
|
|||
/***************************************************************************
|
||||
* Plug-in for MI-0360 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 int mi0360_init(struct sn9c102_device* cam)
|
||||
{
|
||||
struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
|
||||
int err = 0;
|
||||
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x10);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x11);
|
||||
err += sn9c102_write_reg(cam, 0x0a, 0x14);
|
||||
err += sn9c102_write_reg(cam, 0x40, 0x01);
|
||||
err += sn9c102_write_reg(cam, 0x20, 0x17);
|
||||
err += sn9c102_write_reg(cam, 0x07, 0x18);
|
||||
err += sn9c102_write_reg(cam, 0xa0, 0x19);
|
||||
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_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d,
|
||||
0x00, 0x01, 0, 0);
|
||||
err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d,
|
||||
0x00, 0x00, 0, 0);
|
||||
err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03,
|
||||
0x01, 0xe1, 0, 0);
|
||||
err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04,
|
||||
0x02, 0x81, 0, 0);
|
||||
err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05,
|
||||
0x00, 0x17, 0, 0);
|
||||
err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06,
|
||||
0x00, 0x11, 0, 0);
|
||||
err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x62,
|
||||
0x04, 0x9a, 0, 0);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static int mi0360_get_ctrl(struct sn9c102_device* cam,
|
||||
struct v4l2_control* ctrl)
|
||||
{
|
||||
struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
|
||||
u8 data[5+1];
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_EXPOSURE:
|
||||
if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x09,
|
||||
2+1, data) < 0)
|
||||
return -EIO;
|
||||
ctrl->value = data[2];
|
||||
return 0;
|
||||
case V4L2_CID_GAIN:
|
||||
if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x35,
|
||||
2+1, data) < 0)
|
||||
return -EIO;
|
||||
ctrl->value = data[3];
|
||||
return 0;
|
||||
case V4L2_CID_RED_BALANCE:
|
||||
if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2c,
|
||||
2+1, data) < 0)
|
||||
return -EIO;
|
||||
ctrl->value = data[3];
|
||||
return 0;
|
||||
case V4L2_CID_BLUE_BALANCE:
|
||||
if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2d,
|
||||
2+1, data) < 0)
|
||||
return -EIO;
|
||||
ctrl->value = data[3];
|
||||
return 0;
|
||||
case SN9C102_V4L2_CID_GREEN_BALANCE:
|
||||
if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2e,
|
||||
2+1, data) < 0)
|
||||
return -EIO;
|
||||
ctrl->value = data[3];
|
||||
return 0;
|
||||
case V4L2_CID_HFLIP:
|
||||
if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20,
|
||||
2+1, data) < 0)
|
||||
return -EIO;
|
||||
ctrl->value = data[3] & 0x20 ? 1 : 0;
|
||||
return 0;
|
||||
case V4L2_CID_VFLIP:
|
||||
if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20,
|
||||
2+1, data) < 0)
|
||||
return -EIO;
|
||||
ctrl->value = data[3] & 0x80 ? 1 : 0;
|
||||
return 0;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int mi0360_set_ctrl(struct sn9c102_device* cam,
|
||||
const struct v4l2_control* ctrl)
|
||||
{
|
||||
struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
|
||||
int err = 0;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_EXPOSURE:
|
||||
err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
|
||||
0x09, ctrl->value, 0x00,
|
||||
0, 0);
|
||||
break;
|
||||
case V4L2_CID_GAIN:
|
||||
err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
|
||||
0x35, 0x03, ctrl->value,
|
||||
0, 0);
|
||||
break;
|
||||
case V4L2_CID_RED_BALANCE:
|
||||
err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
|
||||
0x2c, 0x03, ctrl->value,
|
||||
0, 0);
|
||||
break;
|
||||
case V4L2_CID_BLUE_BALANCE:
|
||||
err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
|
||||
0x2d, 0x03, ctrl->value,
|
||||
0, 0);
|
||||
break;
|
||||
case SN9C102_V4L2_CID_GREEN_BALANCE:
|
||||
err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
|
||||
0x2b, 0x03, ctrl->value,
|
||||
0, 0);
|
||||
err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
|
||||
0x2e, 0x03, ctrl->value,
|
||||
0, 0);
|
||||
break;
|
||||
case V4L2_CID_HFLIP:
|
||||
err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
|
||||
0x20, ctrl->value ? 0x40:0x00,
|
||||
ctrl->value ? 0x20:0x00,
|
||||
0, 0);
|
||||
break;
|
||||
case V4L2_CID_VFLIP:
|
||||
err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
|
||||
0x20, ctrl->value ? 0x80:0x00,
|
||||
ctrl->value ? 0x80:0x00,
|
||||
0, 0);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return err ? -EIO : 0;
|
||||
}
|
||||
|
||||
|
||||
static int mi0360_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) + 0,
|
||||
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 mi0360_set_pix_format(struct sn9c102_device* cam,
|
||||
const struct v4l2_pix_format* pix)
|
||||
{
|
||||
struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
|
||||
int err = 0;
|
||||
|
||||
if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) {
|
||||
err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
|
||||
0x0a, 0x00, 0x02, 0, 0);
|
||||
err += sn9c102_write_reg(cam, 0x20, 0x19);
|
||||
} else {
|
||||
err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
|
||||
0x0a, 0x00, 0x05, 0, 0);
|
||||
err += sn9c102_write_reg(cam, 0x60, 0x19);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static struct sn9c102_sensor mi0360 = {
|
||||
.name = "MI-0360",
|
||||
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
|
||||
.supported_bridge = BRIDGE_SN9C103,
|
||||
.frequency = SN9C102_I2C_100KHZ,
|
||||
.interface = SN9C102_I2C_2WIRES,
|
||||
.i2c_slave_id = 0x5d,
|
||||
.init = &mi0360_init,
|
||||
.qctrl = {
|
||||
{
|
||||
.id = V4L2_CID_EXPOSURE,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "exposure",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0x0f,
|
||||
.step = 0x01,
|
||||
.default_value = 0x05,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_GAIN,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "global gain",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0x7f,
|
||||
.step = 0x01,
|
||||
.default_value = 0x25,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_HFLIP,
|
||||
.type = V4L2_CTRL_TYPE_BOOLEAN,
|
||||
.name = "horizontal mirror",
|
||||
.minimum = 0,
|
||||
.maximum = 1,
|
||||
.step = 1,
|
||||
.default_value = 0,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_VFLIP,
|
||||
.type = V4L2_CTRL_TYPE_BOOLEAN,
|
||||
.name = "vertical mirror",
|
||||
.minimum = 0,
|
||||
.maximum = 1,
|
||||
.step = 1,
|
||||
.default_value = 0,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_BLUE_BALANCE,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "blue balance",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0x7f,
|
||||
.step = 0x01,
|
||||
.default_value = 0x0f,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = V4L2_CID_RED_BALANCE,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "red balance",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0x7f,
|
||||
.step = 0x01,
|
||||
.default_value = 0x32,
|
||||
.flags = 0,
|
||||
},
|
||||
{
|
||||
.id = SN9C102_V4L2_CID_GREEN_BALANCE,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "green balance",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0x7f,
|
||||
.step = 0x01,
|
||||
.default_value = 0x25,
|
||||
.flags = 0,
|
||||
},
|
||||
},
|
||||
.get_ctrl = &mi0360_get_ctrl,
|
||||
.set_ctrl = &mi0360_set_ctrl,
|
||||
.cropcap = {
|
||||
.bounds = {
|
||||
.left = 0,
|
||||
.top = 0,
|
||||
.width = 640,
|
||||
.height = 480,
|
||||
},
|
||||
.defrect = {
|
||||
.left = 0,
|
||||
.top = 0,
|
||||
.width = 640,
|
||||
.height = 480,
|
||||
},
|
||||
},
|
||||
.set_crop = &mi0360_set_crop,
|
||||
.pix_format = {
|
||||
.width = 640,
|
||||
.height = 480,
|
||||
.pixelformat = V4L2_PIX_FMT_SBGGR8,
|
||||
.priv = 8,
|
||||
},
|
||||
.set_pix_format = &mi0360_set_pix_format
|
||||
};
|
||||
|
||||
|
||||
int sn9c102_probe_mi0360(struct sn9c102_device* cam)
|
||||
{
|
||||
u8 data[5+1];
|
||||
int err = 0;
|
||||
|
||||
err += sn9c102_write_reg(cam, 0x01, 0x01);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x01);
|
||||
err += sn9c102_write_reg(cam, 0x28, 0x17);
|
||||
if (err)
|
||||
return -EIO;
|
||||
|
||||
if (sn9c102_i2c_try_raw_read(cam, &mi0360, mi0360.i2c_slave_id, 0x00,
|
||||
2+1, data) < 0)
|
||||
return -EIO;
|
||||
|
||||
if (data[2] != 0x82 || data[3] != 0x43)
|
||||
return -ENODEV;
|
||||
|
||||
sn9c102_attach_sensor(cam, &mi0360);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -22,9 +22,6 @@
|
|||
#include "sn9c102_sensor.h"
|
||||
|
||||
|
||||
static struct sn9c102_sensor ov7630;
|
||||
|
||||
|
||||
static int ov7630_init(struct sn9c102_device* cam)
|
||||
{
|
||||
int err = 0;
|
||||
|
@ -32,21 +29,21 @@ static int ov7630_init(struct sn9c102_device* cam)
|
|||
switch (sn9c102_get_bridge(cam)) {
|
||||
case BRIDGE_SN9C101:
|
||||
case BRIDGE_SN9C102:
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x14);
|
||||
err += sn9c102_write_reg(cam, 0x60, 0x17);
|
||||
err += sn9c102_write_reg(cam, 0x0f, 0x18);
|
||||
err += sn9c102_write_reg(cam, 0x50, 0x19);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x14);
|
||||
err += sn9c102_write_reg(cam, 0x60, 0x17);
|
||||
err += sn9c102_write_reg(cam, 0x0f, 0x18);
|
||||
err += sn9c102_write_reg(cam, 0x50, 0x19);
|
||||
|
||||
err += sn9c102_i2c_write(cam, 0x12, 0x8d);
|
||||
err += sn9c102_i2c_write(cam, 0x12, 0x0d);
|
||||
err += sn9c102_i2c_write(cam, 0x11, 0x00);
|
||||
err += sn9c102_i2c_write(cam, 0x15, 0x34);
|
||||
err += sn9c102_i2c_write(cam, 0x16, 0x03);
|
||||
err += sn9c102_i2c_write(cam, 0x17, 0x1c);
|
||||
err += sn9c102_i2c_write(cam, 0x18, 0xbd);
|
||||
err += sn9c102_i2c_write(cam, 0x19, 0x06);
|
||||
err += sn9c102_i2c_write(cam, 0x1a, 0xf6);
|
||||
err += sn9c102_i2c_write(cam, 0x1b, 0x04);
|
||||
err += sn9c102_i2c_write(cam, 0x15, 0x35);
|
||||
err += sn9c102_i2c_write(cam, 0x16, 0x03);
|
||||
err += sn9c102_i2c_write(cam, 0x17, 0x1c);
|
||||
err += sn9c102_i2c_write(cam, 0x18, 0xbd);
|
||||
err += sn9c102_i2c_write(cam, 0x19, 0x06);
|
||||
err += sn9c102_i2c_write(cam, 0x1a, 0xf6);
|
||||
err += sn9c102_i2c_write(cam, 0x1b, 0x04);
|
||||
err += sn9c102_i2c_write(cam, 0x20, 0x44);
|
||||
err += sn9c102_i2c_write(cam, 0x23, 0xee);
|
||||
err += sn9c102_i2c_write(cam, 0x26, 0xa0);
|
||||
|
@ -108,23 +105,23 @@ static int ov7630_init(struct sn9c102_device* cam)
|
|||
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, 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);
|
||||
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;
|
||||
|
@ -428,9 +425,9 @@ int sn9c102_probe_ov7630(struct sn9c102_device* cam)
|
|||
switch (sn9c102_get_bridge(cam)) {
|
||||
case BRIDGE_SN9C101:
|
||||
case BRIDGE_SN9C102:
|
||||
err += sn9c102_write_reg(cam, 0x01, 0x01);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x01);
|
||||
err += sn9c102_write_reg(cam, 0x28, 0x17);
|
||||
err += sn9c102_write_reg(cam, 0x01, 0x01);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x01);
|
||||
err += sn9c102_write_reg(cam, 0x28, 0x17);
|
||||
break;
|
||||
case BRIDGE_SN9C103: /* do _not_ change anything! */
|
||||
err += sn9c102_write_reg(cam, 0x09, 0x01);
|
||||
|
|
|
@ -22,9 +22,6 @@
|
|||
#include "sn9c102_sensor.h"
|
||||
|
||||
|
||||
static struct sn9c102_sensor ov7660;
|
||||
|
||||
|
||||
static int ov7660_init(struct sn9c102_device* cam)
|
||||
{
|
||||
int err = 0;
|
||||
|
|
|
@ -23,9 +23,6 @@
|
|||
#include "sn9c102_sensor.h"
|
||||
|
||||
|
||||
static struct sn9c102_sensor pas106b;
|
||||
|
||||
|
||||
static int pas106b_init(struct sn9c102_device* cam)
|
||||
{
|
||||
int err = 0;
|
||||
|
@ -172,7 +169,7 @@ static int pas106b_set_pix_format(struct sn9c102_device* cam,
|
|||
static struct sn9c102_sensor pas106b = {
|
||||
.name = "PAS106B",
|
||||
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
|
||||
.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
|
||||
.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102,
|
||||
.sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
|
||||
.frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
|
||||
.interface = SN9C102_I2C_2WIRES,
|
||||
|
|
|
@ -28,9 +28,6 @@
|
|||
#include "sn9c102_sensor.h"
|
||||
|
||||
|
||||
static struct sn9c102_sensor pas202bcb;
|
||||
|
||||
|
||||
static int pas202bcb_init(struct sn9c102_device* cam)
|
||||
{
|
||||
int err = 0;
|
||||
|
@ -38,12 +35,12 @@ static int pas202bcb_init(struct sn9c102_device* cam)
|
|||
switch (sn9c102_get_bridge(cam)) {
|
||||
case BRIDGE_SN9C101:
|
||||
case BRIDGE_SN9C102:
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x10);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x11);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x14);
|
||||
err += sn9c102_write_reg(cam, 0x20, 0x17);
|
||||
err += sn9c102_write_reg(cam, 0x30, 0x19);
|
||||
err += sn9c102_write_reg(cam, 0x09, 0x18);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x10);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x11);
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x14);
|
||||
err += sn9c102_write_reg(cam, 0x20, 0x17);
|
||||
err += sn9c102_write_reg(cam, 0x30, 0x19);
|
||||
err += sn9c102_write_reg(cam, 0x09, 0x18);
|
||||
break;
|
||||
case BRIDGE_SN9C103:
|
||||
err += sn9c102_write_reg(cam, 0x00, 0x02);
|
||||
|
|
|
@ -22,9 +22,6 @@
|
|||
#include "sn9c102_sensor.h"
|
||||
|
||||
|
||||
static struct sn9c102_sensor tas5110c1b;
|
||||
|
||||
|
||||
static int tas5110c1b_init(struct sn9c102_device* cam)
|
||||
{
|
||||
int err = 0;
|
||||
|
@ -98,7 +95,7 @@ static int tas5110c1b_set_pix_format(struct sn9c102_device* cam,
|
|||
static struct sn9c102_sensor tas5110c1b = {
|
||||
.name = "TAS5110C1B",
|
||||
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
|
||||
.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
|
||||
.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102,
|
||||
.sysfs_ops = SN9C102_I2C_WRITE,
|
||||
.frequency = SN9C102_I2C_100KHZ,
|
||||
.interface = SN9C102_I2C_3WIRES,
|
||||
|
@ -146,7 +143,6 @@ int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam)
|
|||
const struct usb_device_id tas5110c1b_id_table[] = {
|
||||
{ USB_DEVICE(0x0c45, 0x6001), },
|
||||
{ USB_DEVICE(0x0c45, 0x6005), },
|
||||
{ USB_DEVICE(0x0c45, 0x6007), },
|
||||
{ USB_DEVICE(0x0c45, 0x60ab), },
|
||||
{ }
|
||||
};
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
/***************************************************************************
|
||||
* Plug-in for TAS5110D 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 int tas5110d_init(struct sn9c102_device* cam)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
err += sn9c102_write_reg(cam, 0x01, 0x01);
|
||||
err += sn9c102_write_reg(cam, 0x04, 0x01);
|
||||
err += sn9c102_write_reg(cam, 0x0a, 0x14);
|
||||
err += sn9c102_write_reg(cam, 0x60, 0x17);
|
||||
err += sn9c102_write_reg(cam, 0x06, 0x18);
|
||||
err += sn9c102_write_reg(cam, 0xfb, 0x19);
|
||||
|
||||
err += sn9c102_i2c_write(cam, 0x9a, 0xca);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static int tas5110d_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) + 69,
|
||||
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 9;
|
||||
|
||||
err += sn9c102_write_reg(cam, h_start, 0x12);
|
||||
err += sn9c102_write_reg(cam, v_start, 0x13);
|
||||
|
||||
err += sn9c102_write_reg(cam, 0x14, 0x1a);
|
||||
err += sn9c102_write_reg(cam, 0x0a, 0x1b);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static int tas5110d_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, 0x3b, 0x19);
|
||||
else
|
||||
err += sn9c102_write_reg(cam, 0xfb, 0x19);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static struct sn9c102_sensor tas5110d = {
|
||||
.name = "TAS5110D",
|
||||
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
|
||||
.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102,
|
||||
.sysfs_ops = SN9C102_I2C_WRITE,
|
||||
.frequency = SN9C102_I2C_100KHZ,
|
||||
.interface = SN9C102_I2C_2WIRES,
|
||||
.i2c_slave_id = 0x61,
|
||||
.init = &tas5110d_init,
|
||||
.cropcap = {
|
||||
.bounds = {
|
||||
.left = 0,
|
||||
.top = 0,
|
||||
.width = 352,
|
||||
.height = 288,
|
||||
},
|
||||
.defrect = {
|
||||
.left = 0,
|
||||
.top = 0,
|
||||
.width = 352,
|
||||
.height = 288,
|
||||
},
|
||||
},
|
||||
.set_crop = &tas5110d_set_crop,
|
||||
.pix_format = {
|
||||
.width = 352,
|
||||
.height = 288,
|
||||
.pixelformat = V4L2_PIX_FMT_SBGGR8,
|
||||
.priv = 8,
|
||||
},
|
||||
.set_pix_format = &tas5110d_set_pix_format
|
||||
};
|
||||
|
||||
|
||||
int sn9c102_probe_tas5110d(struct sn9c102_device* cam)
|
||||
{
|
||||
const struct usb_device_id tas5110d_id_table[] = {
|
||||
{ USB_DEVICE(0x0c45, 0x6007), },
|
||||
{ }
|
||||
};
|
||||
|
||||
if (!sn9c102_match_id(cam, tas5110d_id_table))
|
||||
return -ENODEV;
|
||||
|
||||
sn9c102_attach_sensor(cam, &tas5110d);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -22,9 +22,6 @@
|
|||
#include "sn9c102_sensor.h"
|
||||
|
||||
|
||||
static struct sn9c102_sensor tas5130d1b;
|
||||
|
||||
|
||||
static int tas5130d1b_init(struct sn9c102_device* cam)
|
||||
{
|
||||
int err = 0;
|
||||
|
@ -99,7 +96,7 @@ static int tas5130d1b_set_pix_format(struct sn9c102_device* cam,
|
|||
static struct sn9c102_sensor tas5130d1b = {
|
||||
.name = "TAS5130D1B",
|
||||
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
|
||||
.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
|
||||
.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102,
|
||||
.sysfs_ops = SN9C102_I2C_WRITE,
|
||||
.frequency = SN9C102_I2C_100KHZ,
|
||||
.interface = SN9C102_I2C_3WIRES,
|
||||
|
|
Загрузка…
Ссылка в новой задаче