From: Hans de Goede Date: Thu, 4 Sep 2008 19:22:57 +0000 (-0300) Subject: V4L/DVB (8873): gspca: Bad image offset with rev012a of spca561 and adjust exposure. X-Git-Tag: v2.6.27-rc6~37^2~4^2~1 X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0fc23d20699a6a3b7e34b3be2cc5e60317ba7849;p=linux-2.6 V4L/DVB (8873): gspca: Bad image offset with rev012a of spca561 and adjust exposure. -Make raw bayer header size change from 20 to 16 affect rev072a only, my 2 rev012a cams both have a header size of 20 -While testing this I also tested the new exposure setting (good work on finding the register JF), and after quite a bit of testing have found out the exact meaning of the register, this patch modifies setexposure to control the exposure over a much wider range. Signed-off-by: Hans de Goede Signed-off-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- diff --git a/drivers/media/video/gspca/spca561.c b/drivers/media/video/gspca/spca561.c index d2f689e366..1c29c279a9 100644 --- a/drivers/media/video/gspca/spca561.c +++ b/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 @@ -648,9 +648,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); @@ -680,23 +702,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); @@ -714,6 +724,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) { @@ -849,6 +860,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, @@ -861,9 +874,13 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, frame, data, len); } else { /* raw bayer (with a header, which we skip) */ -/*fixme: is this specific to the rev012a? */ - data += 16; - len -= 16; + if (sd->chip_revision == Rev012A) { + data += 20; + len -= 20; + } else { + data += 16; + len -= 16; + } gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len); }