Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[media] gspca_pac7302: use registers 0x01 and 0x03 for red and blue balance controls

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>

authored by

Frank Schäfer and committed by
Mauro Carvalho Chehab
2b34e9d1 6f9b3312

+40 -11
+40 -11
drivers/media/usb/gspca/pac7302.c
··· 77 77 * 78 78 * Page | Register | Function 79 79 * -----+------------+--------------------------------------------------- 80 + * 0 | 0x01 | setredbalance() 81 + * 0 | 0x03 | setbluebalance() 80 82 * 0 | 0x0f..0x20 | setcolors() 81 83 * 0 | 0xa2..0xab | setbrightcont() 82 84 * 0 | 0xb6 | setsharpness() 83 - * 0 | 0xc5 | setredbalance() 84 85 * 0 | 0xc6 | setwhitebalance() 85 - * 0 | 0xc7 | setbluebalance() 86 86 * 0 | 0xdc | setbrightcont(), setcolors() 87 87 * 3 | 0x02 | setexposure() 88 88 * 3 | 0x10, 0x12 | setgain() ··· 98 98 /* Include pac common sof detection functions */ 99 99 #include "pac_common.h" 100 100 101 - #define PAC7302_GAIN_DEFAULT 15 102 - #define PAC7302_GAIN_KNEE 42 103 - #define PAC7302_EXPOSURE_DEFAULT 66 /* 33 ms / 30 fps */ 104 - #define PAC7302_EXPOSURE_KNEE 133 /* 66 ms / 15 fps */ 101 + #define PAC7302_RGB_BALANCE_MIN 0 102 + #define PAC7302_RGB_BALANCE_MAX 200 103 + #define PAC7302_RGB_BALANCE_DEFAULT 100 104 + #define PAC7302_GAIN_DEFAULT 15 105 + #define PAC7302_GAIN_KNEE 42 106 + #define PAC7302_EXPOSURE_DEFAULT 66 /* 33 ms / 30 fps */ 107 + #define PAC7302_EXPOSURE_KNEE 133 /* 66 ms / 15 fps */ 105 108 106 109 MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>, " 107 110 "Thomas Kaiser thomas@kaiser-linux.li"); ··· 441 438 reg_w(gspca_dev, 0xdc, 0x01); 442 439 } 443 440 441 + static u8 rgbbalance_ctrl_to_reg_value(s32 rgb_ctrl_val) 442 + { 443 + const unsigned int k = 1000; /* precision factor */ 444 + unsigned int norm; 445 + 446 + /* Normed value [0...k] */ 447 + norm = k * (rgb_ctrl_val - PAC7302_RGB_BALANCE_MIN) 448 + / (PAC7302_RGB_BALANCE_MAX - PAC7302_RGB_BALANCE_MIN); 449 + /* Qudratic apporach improves control at small (register) values: */ 450 + return 64 * norm * norm / (k*k) + 32 * norm / k + 32; 451 + /* Y = 64*X*X + 32*X + 32 452 + * => register values 0x20-0x80; Windows driver uses these limits */ 453 + 454 + /* NOTE: for full value range (0x00-0xff) use 455 + * Y = 254*X*X + X 456 + * => 254 * norm * norm / (k*k) + 1 * norm / k */ 457 + } 458 + 444 459 static void setredbalance(struct gspca_dev *gspca_dev) 445 460 { 446 461 struct sd *sd = (struct sd *) gspca_dev; 447 462 448 - reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ 449 - reg_w(gspca_dev, 0xc5, sd->red_balance->val); 463 + reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ 464 + reg_w(gspca_dev, 0x01, 465 + rgbbalance_ctrl_to_reg_value(sd->red_balance->val)); 450 466 451 467 reg_w(gspca_dev, 0xdc, 0x01); 452 468 } ··· 475 453 struct sd *sd = (struct sd *) gspca_dev; 476 454 477 455 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ 478 - reg_w(gspca_dev, 0xc7, sd->blue_balance->val); 456 + reg_w(gspca_dev, 0x03, 457 + rgbbalance_ctrl_to_reg_value(sd->blue_balance->val)); 479 458 480 459 reg_w(gspca_dev, 0xdc, 0x01); 481 460 } ··· 665 642 V4L2_CID_WHITE_BALANCE_TEMPERATURE, 666 643 0, 255, 1, 55); 667 644 sd->red_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 668 - V4L2_CID_RED_BALANCE, 0, 3, 1, 1); 645 + V4L2_CID_RED_BALANCE, 646 + PAC7302_RGB_BALANCE_MIN, 647 + PAC7302_RGB_BALANCE_MAX, 648 + 1, PAC7302_RGB_BALANCE_DEFAULT); 669 649 sd->blue_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 670 - V4L2_CID_BLUE_BALANCE, 0, 3, 1, 1); 650 + V4L2_CID_BLUE_BALANCE, 651 + PAC7302_RGB_BALANCE_MIN, 652 + PAC7302_RGB_BALANCE_MAX, 653 + 1, PAC7302_RGB_BALANCE_DEFAULT); 671 654 672 655 gspca_dev->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 673 656 V4L2_CID_AUTOGAIN, 0, 1, 1, 1);