#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
 {
        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);
 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);
        setcontrast(gspca_dev);
        setwhite(gspca_dev);
        setautogain(gspca_dev);
+       setexposure(gspca_dev);
 }
 static void sd_start_72a(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,
                                        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);
                }