Commit af67d439 authored by Luca Risolia's avatar Luca Risolia Committed by Greg Kroah-Hartman

[PATCH] USB: SN9C10[12] driver update

This patch brings the driver up to the first stable version.

Changes:

* Remove "redblue" entry under /sys
* Better coding style for comments
* Fix the image downscaling factor calculation
* Fix default color settings for some image sensors
* Fix TAS5130D1B image sensor support
* Other small cleanups
* Remove "EXPERIMENTAL" symbol from KConfig
+ Add support for PAS202BCB sensor (thanks to
  Carlos Eduardo Medaglia Dyonisio)
Signed-off-by: default avatarLuca Risolia <luca.risolia@studio.unibo.it>
Signed-off-by: default avatarGreg Kroah-Hartman <greg@kroah.com>
parent dfe49c2b
......@@ -142,7 +142,7 @@ 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 just one device
Level 3 is useful for testing only, when only one device
is used.
Default: 2
-------------------------------------------------------------------------------
......@@ -153,12 +153,10 @@ Default: 2
It is possible to read and write both the SN9C10[12] and the image sensor
registers by using the "sysfs" filesystem interface.
Every time a supported device is recognized, read-only files named "redblue"
and "green" are created in the /sys/class/video4linux/videoX directory. You can
set the red, blue and green channel's gain by writing the desired value to
them. The value may range from 0 to 15 for each channel; this means that
"redblue" accepts 8-bit values, where the low 4 bits are reserved for red and
the others for blue.
Every time a supported device is recognized, a read-only file named "green" is
created in the /sys/class/video4linux/videoX directory. You can set the green
channel's gain by writing the desired value to it. The value may range from 0
to 15.
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
......@@ -217,6 +215,7 @@ Kernel messages will always tell you whether this is the case:
Model Manufacturer
----- ------------
PAS106B PixArt Imaging Inc.
PAS202BCB PixArt Imaging Inc.
TAS5110C1B Taiwan Advanced Sensor Corporation
TAS5130D1B Taiwan Advanced Sensor Corporation
......@@ -239,8 +238,8 @@ have created for this purpose, which is present in "sn9c102_sensor.h"
(documentation is included there). As an example, have a look at the code in
"sn9c102_pas106b.c", which uses the mentioned interface.
At the moment, not yet supported image sensors are: PAS202B (VGA),
HV7131[D|E1] (VGA), MI03 (VGA), OV7620 (VGA).
At the moment, not yet supported image sensors are: HV7131[D|E1] (VGA),
MI03 (VGA), OV7620 (VGA).
10. Note for V4L2 developers
......@@ -273,4 +272,6 @@ I would thank the following persons:
- Stefano Mozzi, who donated 45 EU;
- Luca Capello for the donation of a webcam;
- Mizuno Takafumi for the donation of a webcam.
- Mizuno Takafumi for the donation of a webcam;
- Carlos Eduardo Medaglia Dyonisio, who added the support for the PAS202BCB
image sensor.
......@@ -163,11 +163,11 @@ config USB_SE401
module will be called se401.
config USB_SN9C102
tristate "USB SN9C10[12] PC Camera Controller support (EXPERIMENTAL)"
depends on USB && VIDEO_DEV && EXPERIMENTAL
tristate "USB SN9C10[12] PC Camera Controller support"
depends on USB && VIDEO_DEV
---help---
Say Y here if you want support for cameras based on SN9C101 and
SN9C102 PC Camera Controllers.
Say Y here if you want support for cameras based on SONiX SN9C101
or SN9C102 PC Camera Controllers.
See <file:Documentation/usb/sn9c102.txt> for more informations.
......
......@@ -31,6 +31,7 @@
#include <linux/types.h>
#include <linux/param.h>
#include <linux/rwsem.h>
#include <asm/semaphore.h>
#include "sn9c102_sensor.h"
......@@ -51,8 +52,8 @@
#define SN9C102_MODULE_AUTHOR "(C) 2004 Luca Risolia"
#define SN9C102_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
#define SN9C102_MODULE_LICENSE "GPL"
#define SN9C102_MODULE_VERSION "1:1.01-beta"
#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 1)
#define SN9C102_MODULE_VERSION "1:1.06"
#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 6)
SN9C102_ID_TABLE;
SN9C102_SENSOR_TABLE;
......
......@@ -83,7 +83,7 @@ MODULE_PARM_DESC(debug,
/*****************************************************************************/
typedef char sn9c102_sof_header_t[7];
typedef char sn9c102_sof_header_t[12];
typedef char sn9c102_eof_header_t[4];
static sn9c102_sof_header_t sn9c102_sof_header[] = {
......@@ -91,8 +91,6 @@ static sn9c102_sof_header_t sn9c102_sof_header[] = {
{0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x01},
};
/* Number of random bytes that complete the SOF above headers */
#define SN9C102_SOFLEN 5
static sn9c102_eof_header_t sn9c102_eof_header[] = {
{0x00, 0x00, 0x00, 0x00},
......@@ -237,9 +235,6 @@ int sn9c102_write_reg(struct sn9c102_device* cam, u8 value, u16 index)
u8* buff = cam->control_buffer;
int res;
if (index == 0x18)
value = (value & 0xcf) | (cam->reg[0x18] & 0x30);
*buff = value;
res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41,
......@@ -443,14 +438,15 @@ int sn9c102_i2c_write(struct sn9c102_device* cam, u8 address, u8 value)
static void* sn9c102_find_sof_header(void* mem, size_t len)
{
size_t soflen=sizeof(sn9c102_sof_header_t), SOFLEN=SN9C102_SOFLEN, i;
size_t soflen = sizeof(sn9c102_sof_header_t), i;
u8 j, n = sizeof(sn9c102_sof_header) / soflen;
for (i = 0; (len >= soflen+SOFLEN) && (i <= len-soflen-SOFLEN); i++)
for (i = 0; (len >= soflen) && (i <= len - soflen); i++)
for (j = 0; j < n; j++)
if (!memcmp(mem + i, sn9c102_sof_header[j], soflen))
/* It's enough to compare 7 bytes */
if (!memcmp(mem + i, sn9c102_sof_header[j], 7))
/* Skips the header */
return mem + i + soflen + SOFLEN;
return mem + i + soflen;
return NULL;
}
......@@ -517,10 +513,12 @@ static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs)
PDBGG("Isochrnous frame: length %u, #%u i", len, i)
/* NOTE: It is probably correct to assume that SOF and EOF
/*
NOTE: It is probably correct to assume that SOF and EOF
headers do not occur between two consecutive packets,
but who knows..Whatever is the truth, this assumption
doesn't introduce bugs. */
doesn't introduce bugs.
*/
redo:
sof = sn9c102_find_sof_header(pos, len);
......@@ -764,9 +762,11 @@ static u8 sn9c102_strtou8(const char* buff, size_t len, ssize_t* count)
return (u8)val;
}
/* NOTE 1: being inside one of the following methods implies that the v4l
/*
NOTE 1: being inside one of the following methods implies that the v4l
device exists for sure (see kobjects and reference counters)
NOTE 2: buffers are PAGE_SIZE long */
NOTE 2: buffers are PAGE_SIZE long
*/
static ssize_t sn9c102_show_reg(struct class_device* cd, char* buf)
{
......@@ -1018,24 +1018,6 @@ sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
}
static ssize_t
sn9c102_store_redblue(struct class_device* cd, const char* buf, size_t len)
{
ssize_t res = 0;
u8 value;
ssize_t count;
value = sn9c102_strtou8(buf, len, &count);
if (!count)
return -EINVAL;
if ((res = sn9c102_store_reg(cd, "0x10", 4)) >= 0)
res = sn9c102_store_val(cd, buf, len);
return res;
}
static ssize_t
sn9c102_store_green(struct class_device* cd, const char* buf, size_t len)
{
......@@ -1062,7 +1044,6 @@ static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR,
sn9c102_show_i2c_reg, sn9c102_store_i2c_reg);
static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
sn9c102_show_i2c_val, sn9c102_store_i2c_val);
static CLASS_DEVICE_ATTR(redblue, S_IWUGO, NULL, sn9c102_store_redblue);
static CLASS_DEVICE_ATTR(green, S_IWUGO, NULL, sn9c102_store_green);
......@@ -1072,7 +1053,6 @@ static void sn9c102_create_sysfs(struct sn9c102_device* cam)
video_device_create_file(v4ldev, &class_device_attr_reg);
video_device_create_file(v4ldev, &class_device_attr_val);
video_device_create_file(v4ldev, &class_device_attr_redblue);
video_device_create_file(v4ldev, &class_device_attr_green);
if (cam->sensor->slave_write_id && cam->sensor->slave_read_id) {
video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
......@@ -1118,10 +1098,6 @@ static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect)
ae_endy = v_size / 2;
int err = 0;
/* These are a sort of stroboscopic signal for some sensors */
err += sn9c102_write_reg(cam, h_size, 0x1a);
err += sn9c102_write_reg(cam, v_size, 0x1b);
err += sn9c102_write_reg(cam, h_start, 0x12);
err += sn9c102_write_reg(cam, v_start, 0x13);
err += sn9c102_write_reg(cam, h_size, 0x15);
......@@ -1134,8 +1110,7 @@ static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect)
return -EIO;
PDBGG("h_start, v_start, h_size, v_size, ho_size, vo_size "
"%u %u %u %u %u %u", h_start, v_start, h_size, v_size, ho_size,
vo_size)
"%u %u %u %u", h_start, v_start, h_size, v_size)
return 0;
}
......@@ -1229,7 +1204,10 @@ static int sn9c102_open(struct inode* inode, struct file* filp)
struct sn9c102_device* cam;
int err = 0;
/* This the only safe way to prevent race conditions with disconnect */
/*
This is the only safe way to prevent race conditions with
disconnect
*/
if (!down_read_trylock(&sn9c102_disconnect))
return -ERESTARTSYS;
......@@ -1727,6 +1705,10 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
return -EINVAL;
}
/* Preserve R,G or B origin */
rect->left &= ~1L;
rect->top &= ~1L;
if (rect->width < 16)
rect->width = 16;
if (rect->height < 16)
......@@ -1747,12 +1729,12 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
rect->width &= ~15L;
rect->height &= ~15L;
{ /* calculate the scaling factor */
{ /* calculate the actual scaling factor */
u32 a, b;
a = rect->width * rect->height;
b = pix_format->width * pix_format->height;
scale = b ? (u8)((a / b) <= 1 ? 1 : ((a / b) == 3 ? 2 :
((a / b) > 4 ? 4 : (a / b)))) : 1;
scale = b ? (u8)((a / b) < 4 ? 1 :
((a / b) < 16 ? 2 : 4)) : 1;
}
if (cam->stream == STREAM_ON) {
......@@ -1879,12 +1861,12 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
memcpy(&rect, &(s->_rect), sizeof(rect));
{ /* calculate the scaling factor */
{ /* calculate the actual scaling factor */
u32 a, b;
a = rect.width * rect.height;
b = pix->width * pix->height;
scale = b ? (u8)((a / b) <= 1 ? 1 : ((a / b) == 3 ? 2 :
((a / b) > 4 ? 4 : (a / b)))) : 1;
scale = b ? (u8)((a / b) < 4 ? 1 :
((a / b) < 16 ? 2 : 4)) : 1;
}
rect.width = scale * pix->width;
......@@ -1895,13 +1877,21 @@ static int sn9c102_v4l2_ioctl(struct inode* inode, struct file* filp,
if (rect.height < 16)
rect.height = 16;
if (rect.width > bounds->left + bounds->width - rect.left)
rect.width = bounds->left+bounds->width - rect.left;
rect.width = bounds->left + bounds->width - rect.left;
if (rect.height > bounds->top + bounds->height - rect.top)
rect.height = bounds->top + bounds->height - rect.top;
rect.width &= ~15L;
rect.height &= ~15L;
{ /* adjust the scaling factor */
u32 a, b;
a = rect.width * rect.height;
b = pix->width * pix->height;
scale = b ? (u8)((a / b) < 4 ? 1 :
((a / b) < 16 ? 2 : 4)) : 1;
}
pix->width = rect.width / scale;
pix->height = rect.height / scale;
......
......@@ -40,13 +40,12 @@ static int pas106b_init(struct sn9c102_device* cam)
err += sn9c102_i2c_write(cam, 0x02, 0x0c);
err += sn9c102_i2c_write(cam, 0x03, 0x12);
err += sn9c102_i2c_write(cam, 0x04, 0x05);
err += sn9c102_i2c_write(cam, 0x05, 0x22);
err += sn9c102_i2c_write(cam, 0x06, 0xac);
err += sn9c102_i2c_write(cam, 0x07, 0x00);
err += sn9c102_i2c_write(cam, 0x05, 0x5a);
err += sn9c102_i2c_write(cam, 0x06, 0x88);
err += sn9c102_i2c_write(cam, 0x07, 0x80);
err += sn9c102_i2c_write(cam, 0x08, 0x01);
err += sn9c102_i2c_write(cam, 0x0a, 0x00);
err += sn9c102_i2c_write(cam, 0x0a, 0x01);
err += sn9c102_i2c_write(cam, 0x0b, 0x00);
err += sn9c102_i2c_write(cam, 0x0d, 0x00);
err += sn9c102_i2c_write(cam, 0x10, 0x06);
err += sn9c102_i2c_write(cam, 0x11, 0x06);
err += sn9c102_i2c_write(cam, 0x12, 0x00);
......@@ -64,11 +63,30 @@ static int pas106b_get_ctrl(struct sn9c102_device* cam,
{
switch (ctrl->id) {
case V4L2_CID_RED_BALANCE:
return (ctrl->value = sn9c102_i2c_read(cam, 0x0c))<0 ? -EIO:0;
if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0)
return -EIO;
ctrl->value &= 0x1f;
return 0;
case V4L2_CID_BLUE_BALANCE:
return (ctrl->value = sn9c102_i2c_read(cam, 0x09))<0 ? -EIO:0;
if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0)
return -EIO;
ctrl->value &= 0x1f;
return 0;
case V4L2_CID_GAIN:
if ((ctrl->value = sn9c102_i2c_read(cam, 0x0e)) < 0)
return -EIO;
ctrl->value &= 0x1f;
return 0;
case V4L2_CID_BRIGHTNESS:
return (ctrl->value = sn9c102_i2c_read(cam, 0x0e))<0 ? -EIO:0;
if ((ctrl->value = sn9c102_i2c_read(cam, 0x0d)) < 0)
return -EIO;
ctrl->value &= 0x1f;
return 0;
case V4L2_CID_CONTRAST:
if ((ctrl->value = sn9c102_i2c_read(cam, 0x0f)) < 0)
return -EIO;
ctrl->value &= 0x07;
return 0;
default:
return -EINVAL;
}
......@@ -87,9 +105,15 @@ static int pas106b_set_ctrl(struct sn9c102_device* cam,
case V4L2_CID_BLUE_BALANCE:
err += sn9c102_i2c_write(cam, 0x09, ctrl->value & 0x1f);
break;
case V4L2_CID_BRIGHTNESS:
case V4L2_CID_GAIN:
err += sn9c102_i2c_write(cam, 0x0e, ctrl->value & 0x1f);
break;
case V4L2_CID_BRIGHTNESS:
err += sn9c102_i2c_write(cam, 0x0d, ctrl->value & 0x1f);
break;
case V4L2_CID_CONTRAST:
err += sn9c102_i2c_write(cam, 0x0f, ctrl->value & 0x03);
break;
default:
return -EINVAL;
}
......@@ -130,7 +154,7 @@ static struct sn9c102_sensor pas106b = {
.minimum = 0x00,
.maximum = 0x1f,
.step = 0x01,
.default_value = 0x03,
.default_value = 0x04,
.flags = 0,
},
{
......@@ -140,19 +164,39 @@ static struct sn9c102_sensor pas106b = {
.minimum = 0x00,
.maximum = 0x1f,
.step = 0x01,
.default_value = 0x02,
.default_value = 0x06,
.flags = 0,
},
{
.id = V4L2_CID_BRIGHTNESS,
.id = V4L2_CID_GAIN,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "brightness",
.name = "global gain",
.minimum = 0x00,
.maximum = 0x1f,
.step = 0x01,
.default_value = 0x06,
.flags = 0,
},
{
.id = V4L2_CID_BRIGHTNESS,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "darkness",
.minimum = 0x00,
.maximum = 0x1f,
.step = 0x01,
.default_value = 0x00,
.flags = 0,
},
{
.id = V4L2_CID_CONTRAST,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "contrast",
.minimum = 0x00,
.maximum = 0x07,
.step = 0x01,
.default_value = 0x00, /* 0x00~0x03 have same effect */
.flags = 0,
},
},
.get_ctrl = &pas106b_get_ctrl,
.set_ctrl = &pas106b_set_ctrl,
......@@ -185,11 +229,13 @@ int sn9c102_probe_pas106b(struct sn9c102_device* cam)
int r0 = 0, r1 = 0, err = 0;
unsigned int pid = 0;
/* Minimal initialization to enable the I2C communication
NOTE: do NOT change the values! */
/*
Minimal initialization to enable the I2C communication
NOTE: do NOT change the values!
*/
err += sn9c102_write_reg(cam, 0x01, 0x01); /* sensor power down */
err += sn9c102_write_reg(cam, 0x00, 0x01); /* sensor power on */
err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 48 MHz */
err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 24 MHz */
if (err)
return -EIO;
......
/***************************************************************************
* Driver for PAS202BCB image sensor connected to the SN9C10[12] PC Camera *
* Controllers *
* *
* Copyright (C) 2004 by Carlos Eduardo Medaglia Dyonisio *
* <medaglia@undl.org.br> *
* http://cadu.homelinux.com:8080/ *
* *
* 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 pas202bcb;
static int pas202bcb_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, 0x20, 0x19);
err += sn9c102_write_reg(cam, 0x09, 0x18);
err += sn9c102_i2c_write(cam, 0x02, 0x0c);
err += sn9c102_i2c_write(cam, 0x03, 0x40);
err += sn9c102_i2c_write(cam, 0x04, 0x07);
err += sn9c102_i2c_write(cam, 0x05, 0x25);
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, 0x08, 0x01);
err += sn9c102_i2c_write(cam, 0x0b, 0x01);
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 pas202bcb_get_ctrl(struct sn9c102_device* cam,
struct v4l2_control* ctrl)
{
switch (ctrl->id) {
case V4L2_CID_RED_BALANCE:
if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0)
return -EIO;
ctrl->value &= 0x0f;
return 0;
case V4L2_CID_BLUE_BALANCE:
if ((ctrl->value = sn9c102_i2c_read(cam, 0x07)) < 0)
return -EIO;
ctrl->value &= 0x0f;
return 0;
case V4L2_CID_GAIN:
if ((ctrl->value = sn9c102_i2c_read(cam, 0x10)) < 0)
return -EIO;
ctrl->value &= 0x1f;
return 0;
case V4L2_CID_BRIGHTNESS:
if ((ctrl->value = sn9c102_i2c_read(cam, 0x06)) < 0)
return -EIO;
ctrl->value &= 0x0f;
return 0;
default:
return -EINVAL;
}
}
static int pas202bcb_set_ctrl(struct sn9c102_device* cam,
const struct v4l2_control* ctrl)
{
int err = 0;
switch (ctrl->id) {
case V4L2_CID_RED_BALANCE:
err += sn9c102_i2c_write(cam, 0x09, ctrl->value & 0x0f);
break;
case V4L2_CID_BLUE_BALANCE:
err += sn9c102_i2c_write(cam, 0x07, ctrl->value & 0x0f);
break;
case V4L2_CID_GAIN:
err += sn9c102_i2c_write(cam, 0x10, ctrl->value & 0x1f);
break;
case V4L2_CID_BRIGHTNESS:
err += sn9c102_i2c_write(cam, 0x06, ctrl->value & 0x0f);
break;
default:
return -EINVAL;
}
err += sn9c102_i2c_write(cam, 0x11, 0x01);
return err;
}
static int pas202bcb_set_crop(struct sn9c102_device* cam,
const struct v4l2_rect* rect)
{
struct sn9c102_sensor* s = &pas202bcb;
int err = 0;
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4,
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 pas202bcb = {
.name = "PAS202BCB",
.maintainer = "Carlos Eduardo Medaglia Dyonisio "
"<medaglia@undl.org.br>",
.frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
.interface = SN9C102_I2C_2WIRES,
.slave_read_id = 0x40,
.slave_write_id = 0x40,
.init = &pas202bcb_init,
.qctrl = {
{
.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 = V4L2_CID_GAIN,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "global gain",
.minimum = 0x00,
.maximum = 0x1f,
.step = 0x01,
.default_value = 0x06,
.flags = 0,
},
{
.id = V4L2_CID_BRIGHTNESS,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "darkness",
.minimum = 0x00,
.maximum = 0x0f,
.step = 0x01,
.default_value = 0x00,
.flags = 0,
},
},
.get_ctrl = &pas202bcb_get_ctrl,
.set_ctrl = &pas202bcb_set_ctrl,
.cropcap = {
.bounds = {
.left = 0,
.top = 0,
.width = 640,
.height = 480,
},
.defrect = {
.left = 0,
.top = 0,
.width = 640,
.height = 480,
},
},
.set_crop = &pas202bcb_set_crop,
.pix_format = {
.width = 640,
.height = 480,
.pixelformat = V4L2_PIX_FMT_SBGGR8,
.priv = 8,
}
};
int sn9c102_probe_pas202bcb(struct sn9c102_device* cam)
{
int r0 = 0, r1 = 0, err = 0;
unsigned int pid = 0;
/*
* Minimal initialization to enable the I2C communication
* NOTE: do NOT change the values!
*/
err += sn9c102_write_reg(cam, 0x01, 0x01); /* sensor power down */
err += sn9c102_write_reg(cam, 0x00, 0x01); /* sensor power on */
err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 24 MHz */
if (err)
return -EIO;
r0 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x00);
r1 = sn9c102_i2c_try_read(cam, &pas202bcb, 0x01);
if (r0 < 0 || r1 < 0)
return -EIO;
pid = (r0 << 4) | ((r1 & 0xf0) >> 4);
if (pid != 0x017)
return -ENODEV;
sn9c102_attach_sensor(cam, &pas202bcb);
return 0;
}
This diff is collapsed.
......@@ -27,16 +27,22 @@ static struct sn9c102_sensor tas5110c1b;
static int tas5110c1b_init(struct sn9c102_device* cam)
{
const u8 DARKNESS = 0xb7;
int err = 0;
err += sn9c102_write_reg(cam, 0x01, 0x01);
err += sn9c102_write_reg(cam, 0x44, 0x01);
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, 0x0a, 0x14);
err += sn9c102_write_reg(cam, 0x60, 0x17);
err += sn9c102_write_reg(cam, 0x06, 0x18);
err += sn9c102_write_reg(cam, 0xcb, 0x19);
err += sn9c102_write_reg(cam, 0xfb, 0x19);
err += sn9c102_i2c_try_raw_write(cam, &tas5110c1b, 4, 0x11, 0x00, 0xc0,
0x80, 0, 0);
err += sn9c102_i2c_try_raw_write(cam, &tas5110c1b, 4, 0x11, 0x02, 0x20,
DARKNESS, 0, 0);
return err;
}
......@@ -53,6 +59,11 @@ static int tas5110c1b_set_crop(struct sn9c102_device* cam,
err += sn9c102_write_reg(cam, h_start, 0x12);
err += sn9c102_write_reg(cam, v_start, 0x13);
/* Don't change ! */
err += sn9c102_write_reg(cam, 0x14, 0x1a);
err += sn9c102_write_reg(cam, 0x0a, 0x1b);
err += sn9c102_write_reg(cam, 0xfb, 0x19);
return err;
}
......@@ -60,6 +71,8 @@ static int tas5110c1b_set_crop(struct sn9c102_device* cam,
static struct sn9c102_sensor tas5110c1b = {
.name = "TAS5110C1B",
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
.frequency = SN9C102_I2C_100KHZ,
.interface = SN9C102_I2C_3WIRES,
.init = &tas5110c1b_init,
.cropcap = {
.bounds = {
......@@ -90,8 +103,9 @@ int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam)
/* This sensor has no identifiers, so let's attach it anyway */
sn9c102_attach_sensor(cam, &tas5110c1b);
/* At the moment, only devices whose PID is 0x6005 have this sensor */
if (tas5110c1b.usbdev->descriptor.idProduct != 0x6005)
/* At the moment, sensor detection is based on USB pid/vid */
if (tas5110c1b.usbdev->descriptor.idProduct != 0x6001 &&
tas5110c1b.usbdev->descriptor.idProduct != 0x6005)
return -ENODEV;
return 0;
......
......@@ -27,6 +27,7 @@ static struct sn9c102_sensor tas5130d1b;
static int tas5130d1b_init(struct sn9c102_device* cam)
{
const u8 DARKNESS = 0xff, CONTRAST = 0xb0, GAIN = 0x08;
int err = 0;
err += sn9c102_write_reg(cam, 0x01, 0x01);
......@@ -37,22 +38,15 @@ static int tas5130d1b_init(struct sn9c102_device* cam)
err += sn9c102_write_reg(cam, 0x00, 0x14);
err += sn9c102_write_reg(cam, 0x60, 0x17);
err += sn9c102_write_reg(cam, 0x07, 0x18);
err += sn9c102_write_reg(cam, 0x33, 0x19);
err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x00, 0x40,
0x47, 0, 0);
err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x02, 0x20,
0xa9, 0, 0);
err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x00, 0x80,
0x00, 0, 0);
err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x00, 0xc0,
0x49, 0, 0);
GAIN, 0, 0);
err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x00, 0x40,
CONTRAST, 0, 0);
err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x02, 0x20,
0x6c, 0, 0);
err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x00, 0xc0,
0x08, 0, 0);
err += sn9c102_i2c_try_raw_write(cam, &tas5130d1b, 4, 0x11, 0x00, 0x20,
0x00, 0, 0);
err += sn9c102_write_reg(cam, 0x63, 0x19);
DARKNESS, 0, 0);
return err;
}
......@@ -62,13 +56,18 @@ static int tas5130d1b_set_crop(struct sn9c102_device* cam,
const struct v4l2_rect* rect)
{
struct sn9c102_sensor* s = &tas5130d1b;
int err = 0;
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 104,
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 12;
int err = 0;
err += sn9c102_write_reg(cam, h_start, 0x12);
err += sn9c102_write_reg(cam, v_start, 0x13);
/* Do NOT change! */
err += sn9c102_write_reg(cam, 0x1d, 0x1a);
err += sn9c102_write_reg(cam, 0x10, 0x1b);
err += sn9c102_write_reg(cam, 0xf3, 0x19);
return err;
}
......@@ -108,13 +107,9 @@ int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam)
/* This sensor has no identifiers, so let's attach it anyway */
sn9c102_attach_sensor(cam, &tas5130d1b);
/* At the moment, only devices whose PID is 0x6025 have this sensor */
/* At the moment, sensor detection is based on USB pid/vid */
if (tas5130d1b.usbdev->descriptor.idProduct != 0x6025)
return -ENODEV;
dev_info(tas5130d1b.dev, "TAS5130D1B detected, but the support for it "
"is disabled at the moment - needs further "
"testing -\n");
return -ENODEV;
return 0;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment