summaryrefslogtreecommitdiff
path: root/linux/drivers/media/video/gspca/spca561.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux/drivers/media/video/gspca/spca561.c')
-rw-r--r--linux/drivers/media/video/gspca/spca561.c111
1 files changed, 75 insertions, 36 deletions
diff --git a/linux/drivers/media/video/gspca/spca561.c b/linux/drivers/media/video/gspca/spca561.c
index d686b6bd7..b1329a149 100644
--- a/linux/drivers/media/video/gspca/spca561.c
+++ b/linux/drivers/media/video/gspca/spca561.c
@@ -38,9 +38,9 @@ struct sd {
#define CONTRAST_MAX 0x3fff
__u16 exposure; /* rev12a only */
-#define EXPOSURE_MIN 0
+#define EXPOSURE_MIN 1
#define EXPOSURE_DEF 200
-#define EXPOSURE_MAX 762
+#define EXPOSURE_MAX (4095 - 900) /* see set_exposure */
__u8 brightness; /* rev72a only */
#define BRIGHTNESS_MIN 0
@@ -73,7 +73,7 @@ struct sd {
#define AG_CNT_START 13
};
-static struct v4l2_pix_format sif_mode[] = {
+static struct v4l2_pix_format sif_012a_mode[] = {
{160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
.bytesperline = 160,
.sizeimage = 160 * 120,
@@ -96,6 +96,29 @@ static struct v4l2_pix_format sif_mode[] = {
.priv = 0},
};
+static struct v4l2_pix_format sif_072a_mode[] = {
+ {160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+ .bytesperline = 160,
+ .sizeimage = 160 * 120,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 3},
+ {176, 144, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+ .bytesperline = 176,
+ .sizeimage = 176 * 144,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 2},
+ {320, 240, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1},
+ {352, 288, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+ .bytesperline = 352,
+ .sizeimage = 352 * 288,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+};
+
/*
* Initialization data
* I'm not very sure how to split initialization from open data
@@ -200,11 +223,11 @@ static int i2c_read(struct gspca_dev *gspca_dev, __u16 reg, __u8 mode)
reg_w_val(gspca_dev->dev, 0x8804, 0x92);
reg_w_val(gspca_dev->dev, 0x8801, reg);
reg_w_val(gspca_dev->dev, 0x8802, (mode | 0x01));
- while (retry--) {
+ do {
reg_r(gspca_dev, 0x8803, 1);
if (!gspca_dev->usb_buf)
break;
- }
+ } while (--retry);
if (retry == 0)
return -1;
reg_r(gspca_dev, 0x8800, 1);
@@ -560,10 +583,15 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam = &gspca_dev->cam;
cam->epaddr = 0x01;
gspca_dev->nbalt = 7 + 1; /* choose alternate 7 first */
- cam->cam_mode = sif_mode;
- cam->nmodes = ARRAY_SIZE(sif_mode);
sd->chip_revision = id->driver_info;
+ if (sd->chip_revision == Rev012A) {
+ cam->cam_mode = sif_012a_mode;
+ cam->nmodes = ARRAY_SIZE(sif_012a_mode);
+ } else {
+ cam->cam_mode = sif_072a_mode;
+ cam->nmodes = ARRAY_SIZE(sif_072a_mode);
+ }
sd->brightness = BRIGHTNESS_DEF;
sd->contrast = CONTRAST_DEF;
sd->white = WHITE_DEF;
@@ -574,14 +602,14 @@ static int sd_config(struct gspca_dev *gspca_dev,
return 0;
}
-/* this function is called at open time */
-static int sd_open_12a(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init_12a(struct gspca_dev *gspca_dev)
{
PDEBUG(D_STREAM, "Chip revision: 012a");
init_161rev12A(gspca_dev);
return 0;
}
-static int sd_open_72a(struct gspca_dev *gspca_dev)
+static int sd_init_72a(struct gspca_dev *gspca_dev)
{
PDEBUG(D_STREAM, "Chip revision: 072a");
write_vector(gspca_dev, spca561_init_data);
@@ -634,9 +662,31 @@ static void setexposure(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
int expo;
+ int clock_divider;
__u8 data[2];
- expo = sd->exposure + 0x20a8; /* from test */
+ /* Register 0x8309 controls exposure for the spca561,
+ the basic exposure setting goes from 1-2047, where 1 is completely
+ dark and 2047 is very bright. It not only influences exposure but
+ also the framerate (to allow for longer exposure) from 1 - 300 it
+ only raises the exposure time then from 300 - 600 it halves the
+ framerate to be able to further raise the exposure time and for every
+ 300 more it halves the framerate again. This allows for a maximum
+ exposure time of circa 0.2 - 0.25 seconds (30 / (2000/3000) fps).
+ Sometimes this is not enough, the 1-2047 uses bits 0-10, bits 11-12
+ configure a divider for the base framerate which us used at the
+ exposure setting of 1-300. These bits configure the base framerate
+ according to the following formula: fps = 60 / (value + 2) */
+ if (sd->exposure < 2048) {
+ expo = sd->exposure;
+ clock_divider = 0;
+ } else {
+ /* Add 900 to make the 0 setting of the second part of the
+ exposure equal to the 2047 setting of the first part. */
+ expo = (sd->exposure - 2048) + 900;
+ clock_divider = 3;
+ }
+ expo |= clock_divider << 11;
data[0] = expo;
data[1] = expo >> 8;
reg_w_buf(gspca_dev, 0x8309, data, 2);
@@ -666,23 +716,11 @@ static void setautogain(struct gspca_dev *gspca_dev)
static void sd_start_12a(struct gspca_dev *gspca_dev)
{
struct usb_device *dev = gspca_dev->dev;
- int Clck;
+ int Clck = 0x8a; /* lower 0x8X values lead to fps > 30 */
__u8 Reg8307[] = { 0xaa, 0x00 };
int mode;
mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
- switch (mode) {
- case 0:
- case 1:
- Clck = 0x8a;
- break;
- case 2:
- Clck = 0x85;
- break;
- default:
- Clck = 0x83;
- break;
- }
if (mode <= 1) {
/* Use compression on 320x240 and above */
reg_w_val(dev, 0x8500, 0x10 | mode);
@@ -700,6 +738,7 @@ static void sd_start_12a(struct gspca_dev *gspca_dev)
setcontrast(gspca_dev);
setwhite(gspca_dev);
setautogain(gspca_dev);
+ setexposure(gspca_dev);
}
static void sd_start_72a(struct gspca_dev *gspca_dev)
{
@@ -747,12 +786,7 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
reg_w_val(gspca_dev->dev, 0x8118, 0x29);
reg_w_val(gspca_dev->dev, 0x8114, 0x08);
}
-}
-
-/* this function is called at close time */
-static void sd_close(struct gspca_dev *gspca_dev)
-{
- reg_w_val(gspca_dev->dev, 0x8114, 0);
+/* reg_w_val(gspca_dev->dev, 0x8114, 0); */
}
static void do_autogain(struct gspca_dev *gspca_dev)
@@ -840,6 +874,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
__u8 *data, /* isoc packet */
int len) /* iso packet length */
{
+ struct sd *sd = (struct sd *) gspca_dev;
+
switch (data[0]) {
case 0: /* start of frame */
frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
@@ -852,8 +888,13 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
frame, data, len);
} else {
/* raw bayer (with a header, which we skip) */
- data += 20;
- len -= 20;
+ if (sd->chip_revision == Rev012A) {
+ data += 20;
+ len -= 20;
+ } else {
+ data += 16;
+ len -= 16;
+ }
gspca_frame_add(gspca_dev, FIRST_PACKET,
frame, data, len);
}
@@ -1135,11 +1176,10 @@ static const struct sd_desc sd_desc_12a = {
.ctrls = sd_ctrls_12a,
.nctrls = ARRAY_SIZE(sd_ctrls_12a),
.config = sd_config,
- .open = sd_open_12a,
+ .init = sd_init_12a,
.start = sd_start_12a,
.stopN = sd_stopN,
.stop0 = sd_stop0,
- .close = sd_close,
.pkt_scan = sd_pkt_scan,
/* .dq_callback = do_autogain, * fixme */
};
@@ -1148,11 +1188,10 @@ static const struct sd_desc sd_desc_72a = {
.ctrls = sd_ctrls_72a,
.nctrls = ARRAY_SIZE(sd_ctrls_72a),
.config = sd_config,
- .open = sd_open_72a,
+ .init = sd_init_72a,
.start = sd_start_72a,
.stopN = sd_stopN,
.stop0 = sd_stop0,
- .close = sd_close,
.pkt_scan = sd_pkt_scan,
.dq_callback = do_autogain,
};