aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/i2c/adv7604.c
diff options
context:
space:
mode:
authorMats Randgaard <matrandg@cisco.com>2013-12-05 08:39:04 -0500
committerMauro Carvalho Chehab <m.chehab@samsung.com>2014-01-07 03:10:00 -0500
commit5c6c634916cab638f474dca20b2fba942cfd6ffc (patch)
tree221f9b1eb793fec3aa850ad4532f69fe0f8d3120 /drivers/media/i2c/adv7604.c
parent1e0b9156d52ac748c92d5aa7ae9dc602168b0b62 (diff)
[media] adv7604: adjust gain and offset for DVI-D signals
If the input signal is DVI-D and quantization range is RGB full range, gain and offset must be adjusted to get the right range on the output. Signed-off-by: Mats Randgaard <matrandg@cisco.com> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
Diffstat (limited to 'drivers/media/i2c/adv7604.c')
-rw-r--r--drivers/media/i2c/adv7604.c98
1 files changed, 89 insertions, 9 deletions
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
index 85caf2451614..d5355d7ba0a0 100644
--- a/drivers/media/i2c/adv7604.c
+++ b/drivers/media/i2c/adv7604.c
@@ -885,12 +885,72 @@ static void configure_custom_video_timings(struct v4l2_subdev *sd,
885 cp_write(sd, 0xac, (height & 0x0f) << 4); 885 cp_write(sd, 0xac, (height & 0x0f) << 4);
886} 886}
887 887
888static void adv7604_set_offset(struct v4l2_subdev *sd, bool auto_offset, u16 offset_a, u16 offset_b, u16 offset_c)
889{
890 struct adv7604_state *state = to_state(sd);
891 u8 offset_buf[4];
892
893 if (auto_offset) {
894 offset_a = 0x3ff;
895 offset_b = 0x3ff;
896 offset_c = 0x3ff;
897 }
898
899 v4l2_dbg(2, debug, sd, "%s: %s offset: a = 0x%x, b = 0x%x, c = 0x%x\n",
900 __func__, auto_offset ? "Auto" : "Manual",
901 offset_a, offset_b, offset_c);
902
903 offset_buf[0] = (cp_read(sd, 0x77) & 0xc0) | ((offset_a & 0x3f0) >> 4);
904 offset_buf[1] = ((offset_a & 0x00f) << 4) | ((offset_b & 0x3c0) >> 6);
905 offset_buf[2] = ((offset_b & 0x03f) << 2) | ((offset_c & 0x300) >> 8);
906 offset_buf[3] = offset_c & 0x0ff;
907
908 /* Registers must be written in this order with no i2c access in between */
909 if (adv_smbus_write_i2c_block_data(state->i2c_cp, 0x77, 4, offset_buf))
910 v4l2_err(sd, "%s: i2c error writing to CP reg 0x77, 0x78, 0x79, 0x7a\n", __func__);
911}
912
913static void adv7604_set_gain(struct v4l2_subdev *sd, bool auto_gain, u16 gain_a, u16 gain_b, u16 gain_c)
914{
915 struct adv7604_state *state = to_state(sd);
916 u8 gain_buf[4];
917 u8 gain_man = 1;
918 u8 agc_mode_man = 1;
919
920 if (auto_gain) {
921 gain_man = 0;
922 agc_mode_man = 0;
923 gain_a = 0x100;
924 gain_b = 0x100;
925 gain_c = 0x100;
926 }
927
928 v4l2_dbg(2, debug, sd, "%s: %s gain: a = 0x%x, b = 0x%x, c = 0x%x\n",
929 __func__, auto_gain ? "Auto" : "Manual",
930 gain_a, gain_b, gain_c);
931
932 gain_buf[0] = ((gain_man << 7) | (agc_mode_man << 6) | ((gain_a & 0x3f0) >> 4));
933 gain_buf[1] = (((gain_a & 0x00f) << 4) | ((gain_b & 0x3c0) >> 6));
934 gain_buf[2] = (((gain_b & 0x03f) << 2) | ((gain_c & 0x300) >> 8));
935 gain_buf[3] = ((gain_c & 0x0ff));
936
937 /* Registers must be written in this order with no i2c access in between */
938 if (adv_smbus_write_i2c_block_data(state->i2c_cp, 0x73, 4, gain_buf))
939 v4l2_err(sd, "%s: i2c error writing to CP reg 0x73, 0x74, 0x75, 0x76\n", __func__);
940}
941
888static void set_rgb_quantization_range(struct v4l2_subdev *sd) 942static void set_rgb_quantization_range(struct v4l2_subdev *sd)
889{ 943{
890 struct adv7604_state *state = to_state(sd); 944 struct adv7604_state *state = to_state(sd);
945 bool rgb_output = io_read(sd, 0x02) & 0x02;
946 bool hdmi_signal = hdmi_read(sd, 0x05) & 0x80;
947
948 v4l2_dbg(2, debug, sd, "%s: RGB quantization range: %d, RGB out: %d, HDMI: %d\n",
949 __func__, state->rgb_quantization_range,
950 rgb_output, hdmi_signal);
891 951
892 v4l2_dbg(2, debug, sd, "%s: rgb_quantization_range = %d\n", 952 adv7604_set_gain(sd, true, 0x0, 0x0, 0x0);
893 __func__, state->rgb_quantization_range); 953 adv7604_set_offset(sd, true, 0x0, 0x0, 0x0);
894 954
895 switch (state->rgb_quantization_range) { 955 switch (state->rgb_quantization_range) {
896 case V4L2_DV_RGB_RANGE_AUTO: 956 case V4L2_DV_RGB_RANGE_AUTO:
@@ -908,7 +968,7 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd)
908 break; 968 break;
909 } 969 }
910 970
911 if (hdmi_read(sd, 0x05) & 0x80) { 971 if (hdmi_signal) {
912 /* Receiving HDMI signal 972 /* Receiving HDMI signal
913 * Set automode */ 973 * Set automode */
914 io_write_and_or(sd, 0x02, 0x0f, 0xf0); 974 io_write_and_or(sd, 0x02, 0x0f, 0xf0);
@@ -924,24 +984,45 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd)
924 } else { 984 } else {
925 /* RGB full range (0-255) */ 985 /* RGB full range (0-255) */
926 io_write_and_or(sd, 0x02, 0x0f, 0x10); 986 io_write_and_or(sd, 0x02, 0x0f, 0x10);
987
988 if (is_digital_input(sd) && rgb_output) {
989 adv7604_set_offset(sd, false, 0x40, 0x40, 0x40);
990 } else {
991 adv7604_set_gain(sd, false, 0xe0, 0xe0, 0xe0);
992 adv7604_set_offset(sd, false, 0x70, 0x70, 0x70);
993 }
927 } 994 }
928 break; 995 break;
929 case V4L2_DV_RGB_RANGE_LIMITED: 996 case V4L2_DV_RGB_RANGE_LIMITED:
930 if (state->selected_input == ADV7604_INPUT_VGA_COMP) { 997 if (state->selected_input == ADV7604_INPUT_VGA_COMP) {
931 /* YCrCb limited range (16-235) */ 998 /* YCrCb limited range (16-235) */
932 io_write_and_or(sd, 0x02, 0x0f, 0x20); 999 io_write_and_or(sd, 0x02, 0x0f, 0x20);
933 } else { 1000 break;
934 /* RGB limited range (16-235) */
935 io_write_and_or(sd, 0x02, 0x0f, 0x00);
936 } 1001 }
1002
1003 /* RGB limited range (16-235) */
1004 io_write_and_or(sd, 0x02, 0x0f, 0x00);
1005
937 break; 1006 break;
938 case V4L2_DV_RGB_RANGE_FULL: 1007 case V4L2_DV_RGB_RANGE_FULL:
939 if (state->selected_input == ADV7604_INPUT_VGA_COMP) { 1008 if (state->selected_input == ADV7604_INPUT_VGA_COMP) {
940 /* YCrCb full range (0-255) */ 1009 /* YCrCb full range (0-255) */
941 io_write_and_or(sd, 0x02, 0x0f, 0x60); 1010 io_write_and_or(sd, 0x02, 0x0f, 0x60);
1011 break;
1012 }
1013
1014 /* RGB full range (0-255) */
1015 io_write_and_or(sd, 0x02, 0x0f, 0x10);
1016
1017 if (is_analog_input(sd) || hdmi_signal)
1018 break;
1019
1020 /* Adjust gain/offset for DVI-D signals only */
1021 if (rgb_output) {
1022 adv7604_set_offset(sd, false, 0x40, 0x40, 0x40);
942 } else { 1023 } else {
943 /* RGB full range (0-255) */ 1024 adv7604_set_gain(sd, false, 0xe0, 0xe0, 0xe0);
944 io_write_and_or(sd, 0x02, 0x0f, 0x10); 1025 adv7604_set_offset(sd, false, 0x70, 0x70, 0x70);
945 } 1026 }
946 break; 1027 break;
947 } 1028 }
@@ -1367,7 +1448,6 @@ static int adv7604_s_dv_timings(struct v4l2_subdev *sd,
1367 1448
1368 set_rgb_quantization_range(sd); 1449 set_rgb_quantization_range(sd);
1369 1450
1370
1371 if (debug > 1) 1451 if (debug > 1)
1372 v4l2_print_dv_timings(sd->name, "adv7604_s_dv_timings: ", 1452 v4l2_print_dv_timings(sd->name, "adv7604_s_dv_timings: ",
1373 timings, true); 1453 timings, true);