[media] gspca_pac7302: use registers 0x01 and 0x03 for red and blue balance controls
authorFrank Schäfer <fschaefer.oss@googlemail.com>
Sun, 23 Sep 2012 13:29:43 +0000 (10:29 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Wed, 21 Nov 2012 15:03:10 +0000 (13:03 -0200)
Currently used registers 0xc5 and 0xc7 provide only a very coarse
adjustment possibility within a very small value range (0-3).
With registers 0x01 and 0x03, a fine grained adjustment with
255 steps is possible. This is also what the Windows driver does.

Signed-off-by: Frank Schäfer <fschaefer.oss@googlemail.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/usb/gspca/pac7302.c

index 4894ac19b0328d67b05ea2954fd2d88bdb3eb8c0..4f5869a98082201e2ef39d8bb3f009b0972826a4 100644 (file)
  *
  * Page | Register   | Function
  * -----+------------+---------------------------------------------------
+ *  0   | 0x01       | setredbalance()
+ *  0   | 0x03       | setbluebalance()
  *  0   | 0x0f..0x20 | setcolors()
  *  0   | 0xa2..0xab | setbrightcont()
  *  0   | 0xb6       | setsharpness()
- *  0   | 0xc5       | setredbalance()
  *  0   | 0xc6       | setwhitebalance()
- *  0   | 0xc7       | setbluebalance()
  *  0   | 0xdc       | setbrightcont(), setcolors()
  *  3   | 0x02       | setexposure()
  *  3   | 0x10, 0x12 | setgain()
 /* Include pac common sof detection functions */
 #include "pac_common.h"
 
-#define PAC7302_GAIN_DEFAULT      15
-#define PAC7302_GAIN_KNEE         42
-#define PAC7302_EXPOSURE_DEFAULT  66 /* 33 ms / 30 fps */
-#define PAC7302_EXPOSURE_KNEE    133 /* 66 ms / 15 fps */
+#define PAC7302_RGB_BALANCE_MIN                  0
+#define PAC7302_RGB_BALANCE_MAX                200
+#define PAC7302_RGB_BALANCE_DEFAULT    100
+#define PAC7302_GAIN_DEFAULT            15
+#define PAC7302_GAIN_KNEE               42
+#define PAC7302_EXPOSURE_DEFAULT        66 /* 33 ms / 30 fps */
+#define PAC7302_EXPOSURE_KNEE          133 /* 66 ms / 15 fps */
 
 MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>, "
                "Thomas Kaiser thomas@kaiser-linux.li");
@@ -438,12 +441,31 @@ static void setwhitebalance(struct gspca_dev *gspca_dev)
        reg_w(gspca_dev, 0xdc, 0x01);
 }
 
+static u8 rgbbalance_ctrl_to_reg_value(s32 rgb_ctrl_val)
+{
+       const unsigned int k = 1000;    /* precision factor */
+       unsigned int norm;
+
+       /* Normed value [0...k] */
+       norm = k * (rgb_ctrl_val - PAC7302_RGB_BALANCE_MIN)
+                   / (PAC7302_RGB_BALANCE_MAX - PAC7302_RGB_BALANCE_MIN);
+       /* Qudratic apporach improves control at small (register) values: */
+       return 64 * norm * norm / (k*k)  +  32 * norm / k  +  32;
+       /* Y = 64*X*X + 32*X + 32
+        * => register values 0x20-0x80; Windows driver uses these limits */
+
+       /* NOTE: for full value range (0x00-0xff) use
+        *         Y = 254*X*X + X
+        *         => 254 * norm * norm / (k*k)  +  1 * norm / k        */
+}
+
 static void setredbalance(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       reg_w(gspca_dev, 0xff, 0x00);           /* page 0 */
-       reg_w(gspca_dev, 0xc5, sd->red_balance->val);
+       reg_w(gspca_dev, 0xff, 0x00);                   /* page 0 */
+       reg_w(gspca_dev, 0x01,
+             rgbbalance_ctrl_to_reg_value(sd->red_balance->val));
 
        reg_w(gspca_dev, 0xdc, 0x01);
 }
@@ -453,7 +475,8 @@ static void setbluebalance(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
 
        reg_w(gspca_dev, 0xff, 0x00);                   /* page 0 */
-       reg_w(gspca_dev, 0xc7, sd->blue_balance->val);
+       reg_w(gspca_dev, 0x03,
+             rgbbalance_ctrl_to_reg_value(sd->blue_balance->val));
 
        reg_w(gspca_dev, 0xdc, 0x01);
 }
@@ -642,9 +665,15 @@ static int sd_init_controls(struct gspca_dev *gspca_dev)
                                        V4L2_CID_WHITE_BALANCE_TEMPERATURE,
                                        0, 255, 1, 55);
        sd->red_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
-                                       V4L2_CID_RED_BALANCE, 0, 3, 1, 1);
+                                       V4L2_CID_RED_BALANCE,
+                                       PAC7302_RGB_BALANCE_MIN,
+                                       PAC7302_RGB_BALANCE_MAX,
+                                       1, PAC7302_RGB_BALANCE_DEFAULT);
        sd->blue_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
-                                       V4L2_CID_BLUE_BALANCE, 0, 3, 1, 1);
+                                       V4L2_CID_BLUE_BALANCE,
+                                       PAC7302_RGB_BALANCE_MIN,
+                                       PAC7302_RGB_BALANCE_MAX,
+                                       1, PAC7302_RGB_BALANCE_DEFAULT);
 
        gspca_dev->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
                                        V4L2_CID_AUTOGAIN, 0, 1, 1, 1);