summaryrefslogtreecommitdiff
path: root/drivers/media/video/gspca/sonixb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/gspca/sonixb.c')
-rw-r--r--drivers/media/video/gspca/sonixb.c101
1 files changed, 80 insertions, 21 deletions
diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c
index 81a7dd6a7240..43a7721d669c 100644
--- a/drivers/media/video/gspca/sonixb.c
+++ b/drivers/media/video/gspca/sonixb.c
@@ -188,8 +188,8 @@ static const struct ctrl sd_ctrls[] = {
.id = V4L2_CID_EXPOSURE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Exposure",
-#define EXPOSURE_DEF 66 /* 33 ms / 30 fps (except on PAS202) */
-#define EXPOSURE_KNEE 200 /* 100 ms / 10 fps (except on PAS202) */
+#define EXPOSURE_DEF 66 /* 33 ms / 30 fps (except on PASXXX) */
+#define EXPOSURE_KNEE 200 /* 100 ms / 10 fps (except on PASXXX) */
.minimum = 0,
.maximum = 1023,
.step = 1,
@@ -408,6 +408,30 @@ static const __u8 initPas106[] = {
0x18, 0x10, 0x02, 0x02, 0x09, 0x07
};
/* compression 0x86 mckinit1 0x2b */
+
+/* "Known" PAS106B registers:
+ 0x02 clock divider
+ 0x03 Variable framerate bits 4-11
+ 0x04 Var framerate bits 0-3, one must leave the 4 msb's at 0 !!
+ The variable framerate control must never be set lower then 300,
+ which sets the framerate at 90 / reg02, otherwise vsync is lost.
+ 0x05 Shutter Time Line Offset, this can be used as an exposure control:
+ 0 = use full frame time, 255 = no exposure at all
+ Note this may never be larger then "var-framerate control" / 2 - 2.
+ When var-framerate control is < 514, no exposure is reached at the max
+ allowed value for the framerate control value, rather then at 255.
+ 0x06 Shutter Time Pixel Offset, like reg05 this influences exposure, but
+ only a very little bit, leave at 0xcd
+ 0x07 offset sign bit (bit0 1 > negative offset)
+ 0x08 offset
+ 0x09 Blue Gain
+ 0x0a Green1 Gain
+ 0x0b Green2 Gain
+ 0x0c Red Gain
+ 0x0e Global gain
+ 0x13 Write 1 to commit settings to sensor
+*/
+
static const __u8 pas106_sensor_init[][8] = {
/* Pixel Clock Divider 6 */
{ 0xa1, 0x40, 0x02, 0x04, 0x00, 0x00, 0x00, 0x14 },
@@ -532,7 +556,7 @@ SENS(initHv7131, NULL, hv7131_sensor_init, NULL, NULL, 0, NO_EXPO|NO_FREQ, 0),
SENS(initOv6650, NULL, ov6650_sensor_init, NULL, NULL, F_GAIN|F_SIF, 0, 0x60),
SENS(initOv7630, initOv7630_3, ov7630_sensor_init, NULL, ov7630_sensor_init_3,
F_GAIN, 0, 0x21),
-SENS(initPas106, NULL, pas106_sensor_init, NULL, NULL, F_SIF, NO_EXPO|NO_FREQ,
+SENS(initPas106, NULL, pas106_sensor_init, NULL, NULL, F_GAIN|F_SIF, NO_FREQ,
0),
SENS(initPas202, initPas202, pas202_sensor_init, NULL, NULL, F_GAIN,
NO_FREQ, 0),
@@ -628,26 +652,19 @@ static void setbrightness(struct gspca_dev *gspca_dev)
goto err;
break;
}
- case SENSOR_PAS106: {
- __u8 i2c1[] =
- {0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14};
-
- i2c1[3] = sd->brightness >> 3;
- i2c1[2] = 0x0e;
- if (i2c_w(gspca_dev, i2c1) < 0)
- goto err;
- i2c1[3] = 0x01;
- i2c1[2] = 0x13;
- if (i2c_w(gspca_dev, i2c1) < 0)
- goto err;
- break;
- }
+ case SENSOR_PAS106:
case SENSOR_PAS202: {
__u8 i2cpbright[] =
{0xb0, 0x40, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x16};
- const __u8 i2cpdoit[] =
+ __u8 i2cpdoit[] =
{0xa0, 0x40, 0x11, 0x01, 0x00, 0x00, 0x00, 0x16};
+ /* PAS106 uses reg 7 and 8 instead of b and c */
+ if (sd->sensor == SENSOR_PAS106) {
+ i2cpbright[2] = 7;
+ i2cpdoit[2] = 0x13;
+ }
+
if (sd->brightness < 127) {
/* change reg 0x0b, signreg */
i2cpbright[3] = 0x01;
@@ -709,18 +726,28 @@ static void setsensorgain(struct gspca_dev *gspca_dev)
goto err;
break;
}
+ case SENSOR_PAS106:
case SENSOR_PAS202: {
__u8 i2cpgain[] =
- {0xa0, 0x40, 0x10, 0x00, 0x00, 0x00, 0x63, 0x15};
+ {0xa0, 0x40, 0x10, 0x00, 0x00, 0x00, 0x00, 0x15};
__u8 i2cpcolorgain[] =
{0xc0, 0x40, 0x07, 0x00, 0x00, 0x00, 0x00, 0x15};
- const __u8 i2cpdoit[] =
- {0xa0, 0x40, 0x11, 0x01, 0x00, 0x00, 0x63, 0x16};
+ __u8 i2cpdoit[] =
+ {0xa0, 0x40, 0x11, 0x01, 0x00, 0x00, 0x00, 0x16};
+
+ /* PAS106 uses different regs (and has split green gains) */
+ if (sd->sensor == SENSOR_PAS106) {
+ i2cpgain[2] = 0x0e;
+ i2cpcolorgain[0] = 0xd0;
+ i2cpcolorgain[2] = 0x09;
+ i2cpdoit[2] = 0x13;
+ }
i2cpgain[3] = sd->gain >> 3;
i2cpcolorgain[3] = sd->gain >> 4;
i2cpcolorgain[4] = sd->gain >> 4;
i2cpcolorgain[5] = sd->gain >> 4;
+ i2cpcolorgain[6] = sd->gain >> 4;
if (i2c_w(gspca_dev, i2cpgain) < 0)
goto err;
@@ -883,6 +910,38 @@ static void setexposure(struct gspca_dev *gspca_dev)
goto err;
break;
}
+ case SENSOR_PAS106: {
+ __u8 i2cpframerate[] =
+ {0xb1, 0x40, 0x03, 0x00, 0x00, 0x00, 0x00, 0x14};
+ __u8 i2cpexpo[] =
+ {0xa1, 0x40, 0x05, 0x00, 0x00, 0x00, 0x00, 0x14};
+ const __u8 i2cpdoit[] =
+ {0xa1, 0x40, 0x13, 0x01, 0x00, 0x00, 0x00, 0x14};
+ int framerate_ctrl;
+
+ /* For values below 150 use partial frame exposure, above
+ that use framerate ctrl */
+ if (sd->exposure < 150) {
+ i2cpexpo[3] = 150 - sd->exposure;
+ framerate_ctrl = 300;
+ } else {
+ /* The PAS106's exposure control goes from 0 - 4095,
+ but anything below 300 causes vsync issues, so scale
+ our 150-1023 to 300-4095 */
+ framerate_ctrl = (sd->exposure - 150) * 1000 / 230 +
+ 300;
+ }
+
+ i2cpframerate[3] = framerate_ctrl >> 4;
+ i2cpframerate[4] = framerate_ctrl & 0x0f;
+ if (i2c_w(gspca_dev, i2cpframerate) < 0)
+ goto err;
+ if (i2c_w(gspca_dev, i2cpexpo) < 0)
+ goto err;
+ if (i2c_w(gspca_dev, i2cpdoit) < 0)
+ goto err;
+ break;
+ }
}
return;
err: