diff options
author | Mauro Carvalho Chehab <mchehab@infradead.org> | 2006-09-02 11:59:38 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2006-09-26 11:30:35 -0400 |
commit | d9dce96faec043f261dc5a57d43cfc0e2905f2a5 (patch) | |
tree | b148fe4eb3ef007702e55aa6db0600b770349579 /drivers | |
parent | 3e7d3e57350ab8b7b8ce930074a31c87f1cbc8cc (diff) |
V4L/DVB (4592): Fixes some troubles on saa7115
Scaling were not working fine;
Some reserved registers were wrong;
On some situations, saa7115 were not properly being initializated.
Removed some duplicated code.
Thanks-to: Hans Verkuil <hverkuil@xs4all.nl> for co-working on this
patch.
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/video/saa7115.c | 288 |
1 files changed, 141 insertions, 147 deletions
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index 327a43d5116b..61642f83c957 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c | |||
@@ -48,6 +48,8 @@ | |||
48 | #include <media/saa7115.h> | 48 | #include <media/saa7115.h> |
49 | #include <asm/div64.h> | 49 | #include <asm/div64.h> |
50 | 50 | ||
51 | #define HRES_60HZ (480+16) | ||
52 | |||
51 | MODULE_DESCRIPTION("Philips SAA7111/SAA7113/SAA7114/SAA7115/SAA7118 video decoder driver"); | 53 | MODULE_DESCRIPTION("Philips SAA7111/SAA7113/SAA7114/SAA7115/SAA7118 video decoder driver"); |
52 | MODULE_AUTHOR( "Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, " | 54 | MODULE_AUTHOR( "Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, " |
53 | "Hans Verkuil, Mauro Carvalho Chehab"); | 55 | "Hans Verkuil, Mauro Carvalho Chehab"); |
@@ -75,6 +77,8 @@ struct saa711x_state { | |||
75 | int contrast; | 77 | int contrast; |
76 | int hue; | 78 | int hue; |
77 | int sat; | 79 | int sat; |
80 | int width; | ||
81 | int height; | ||
78 | enum v4l2_chip_ident ident; | 82 | enum v4l2_chip_ident ident; |
79 | u32 audclk_freq; | 83 | u32 audclk_freq; |
80 | u32 crystal_freq; | 84 | u32 crystal_freq; |
@@ -93,40 +97,32 @@ static inline int saa711x_write(struct i2c_client *client, u8 reg, u8 value) | |||
93 | /* Sanity routine to check if a register is present */ | 97 | /* Sanity routine to check if a register is present */ |
94 | static int saa711x_has_reg(const int id, const u8 reg) | 98 | static int saa711x_has_reg(const int id, const u8 reg) |
95 | { | 99 | { |
100 | if (id == V4L2_IDENT_SAA7111) | ||
101 | return reg < 0x20 && reg != 0x01 && reg != 0x0f && | ||
102 | (reg < 0x13 || reg > 0x19) && reg != 0x1d && reg != 0x1e; | ||
103 | |||
104 | /* common for saa7113/4/5/8 */ | ||
105 | if (unlikely((reg >= 0x3b && reg <= 0x3f) || reg == 0x5c || reg == 0x5f || | ||
106 | reg == 0xa3 || reg == 0xa7 || reg == 0xab || reg == 0xaf || (reg >= 0xb5 && reg <= 0xb7) || | ||
107 | reg == 0xd3 || reg == 0xd7 || reg == 0xdb || reg == 0xdf || (reg >= 0xe5 && reg <= 0xe7) || | ||
108 | reg == 0x82 || (reg >= 0x89 && reg <= 0x8e))) | ||
109 | return 0; | ||
110 | |||
96 | switch (id) { | 111 | switch (id) { |
97 | case V4L2_IDENT_SAA7111: | ||
98 | if (reg>0x1f || reg==1 || reg==0x0f || reg==0x14 || reg==0x18 | ||
99 | || reg==0x19 || reg==0x1d || reg==0x1e) | ||
100 | return 0; | ||
101 | break; | ||
102 | case V4L2_IDENT_SAA7113: | 112 | case V4L2_IDENT_SAA7113: |
103 | if (reg>0x62 || reg==0x14 || (reg>=0x18 && reg<=0x1e) || | 113 | return reg != 0x14 && (reg < 0x18 || reg > 0x1e) && (reg < 0x20 || reg > 0x3f) && |
104 | (reg>=0x20 && reg<=0x3f) ||reg==0x5f ) | 114 | reg != 0x5d && reg < 0x63; |
105 | return 0; | ||
106 | break; | ||
107 | case V4L2_IDENT_SAA7114: | 115 | case V4L2_IDENT_SAA7114: |
108 | if (reg>=0xf0 || (reg>=0x1a && reg<=0x1e) || | 116 | return (reg < 0x1a || reg > 0x1e) && (reg < 0x20 || reg > 0x2f) && |
109 | (reg>=0x20 && reg<=0x2f) || | 117 | (reg < 0x63 || reg > 0x7f) && reg != 0x33 && reg != 0x37 && |
110 | (reg>=0x63 && reg<=0x7f) ) | 118 | reg != 0x81 && reg < 0xf0; |
111 | return 0; | ||
112 | break; | ||
113 | case V4L2_IDENT_SAA7115: | 119 | case V4L2_IDENT_SAA7115: |
114 | if ((reg>=0x20 && reg<=0x2f) || (reg==0x5c) || | 120 | return (reg < 0x20 || reg > 0x2f) && reg != 0x65 && (reg < 0xfc || reg > 0xfe); |
115 | (reg>=0xfc && reg<=0xfe) ) | ||
116 | return 0; | ||
117 | break; | ||
118 | case V4L2_IDENT_SAA7118: | 121 | case V4L2_IDENT_SAA7118: |
119 | if (reg>=0xf0 || (reg>=0x1a && reg<=0x1d) || | 122 | return (reg < 0x1a || reg > 0x1d) && (reg < 0x20 || reg > 0x22) && |
120 | (reg>=0x63 && reg<=0x6f) ) | 123 | (reg < 0x26 || reg > 0x28) && reg != 0x33 && reg != 0x37 && |
121 | return 0; | 124 | (reg < 0x63 || reg > 0x7f) && reg != 0x81 && reg < 0xf0; |
122 | } | 125 | } |
123 | |||
124 | /* Those registers are reserved for all family */ | ||
125 | if (unlikely((reg>=0x20 && reg<=0x22) || | ||
126 | (reg>=0x26 && reg<=0x28) || | ||
127 | (reg>=0x3b && reg<=0x3f) || (reg==0x5f) || | ||
128 | (reg>=0x63 && reg<=0x6f) ) ) | ||
129 | return 0; | ||
130 | return 1; | 126 | return 1; |
131 | } | 127 | } |
132 | 128 | ||
@@ -258,6 +254,9 @@ static const unsigned char saa7115_init_auto_input[] = { | |||
258 | R_1C_ENHAN_COMB_CTRL1, 0xa9, /* recommended value */ | 254 | R_1C_ENHAN_COMB_CTRL1, 0xa9, /* recommended value */ |
259 | R_1D_ENHAN_COMB_CTRL2, 0x01, /* recommended value */ | 255 | R_1D_ENHAN_COMB_CTRL2, 0x01, /* recommended value */ |
260 | 256 | ||
257 | |||
258 | R_80_GLOBAL_CNTL_1, 0x0, /* No tasks enabled at init */ | ||
259 | |||
261 | /* Power Device Control */ | 260 | /* Power Device Control */ |
262 | R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset device */ | 261 | R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset device */ |
263 | R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* set device programmed, all in operational mode */ | 262 | R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* set device programmed, all in operational mode */ |
@@ -333,8 +332,8 @@ static const unsigned char saa7115_cfg_60hz_video[] = { | |||
333 | R_C9_B_VERT_INPUT_WINDOW_START_MSB, 0x00, | 332 | R_C9_B_VERT_INPUT_WINDOW_START_MSB, 0x00, |
334 | 333 | ||
335 | /* vwindow length 0xf8 = 248 */ | 334 | /* vwindow length 0xf8 = 248 */ |
336 | R_CA_B_VERT_INPUT_WINDOW_LENGTH, 0xf8, | 335 | R_CA_B_VERT_INPUT_WINDOW_LENGTH, HRES_60HZ>>1, |
337 | R_CB_B_VERT_INPUT_WINDOW_LENGTH_MSB, 0x00, | 336 | R_CB_B_VERT_INPUT_WINDOW_LENGTH_MSB, HRES_60HZ>>9, |
338 | 337 | ||
339 | /* hwindow 0x02d0 = 720 */ | 338 | /* hwindow 0x02d0 = 720 */ |
340 | R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0, | 339 | R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0, |
@@ -345,11 +344,6 @@ static const unsigned char saa7115_cfg_60hz_video[] = { | |||
345 | R_F5_PULSGEN_LINE_LENGTH, 0xad, | 344 | R_F5_PULSGEN_LINE_LENGTH, 0xad, |
346 | R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG, 0x01, | 345 | R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG, 0x01, |
347 | 346 | ||
348 | R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x00, /* Disable I-port output */ | ||
349 | R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */ | ||
350 | R_80_GLOBAL_CNTL_1, 0x20, /* Activate only task "B", continuous mode (was 0xA0) */ | ||
351 | R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */ | ||
352 | R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* Enable I-port output */ | ||
353 | 0x00, 0x00 | 347 | 0x00, 0x00 |
354 | }; | 348 | }; |
355 | 349 | ||
@@ -423,21 +417,11 @@ static const unsigned char saa7115_cfg_50hz_video[] = { | |||
423 | R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0, | 417 | R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0, |
424 | R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x02, | 418 | R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x02, |
425 | 419 | ||
426 | /* vsize 0x0120 = 288 */ | ||
427 | R_CE_B_VERT_OUTPUT_WINDOW_LENGTH, 0x20, | ||
428 | R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x01, | ||
429 | |||
430 | R_F0_LFCO_PER_LINE, 0xb0, /* Set PLL Register. 50hz 625 lines per frame, 27 MHz */ | 420 | R_F0_LFCO_PER_LINE, 0xb0, /* Set PLL Register. 50hz 625 lines per frame, 27 MHz */ |
431 | R_F1_P_I_PARAM_SELECT, 0x05, /* low bit with 0xF0, (was 0x05) */ | 421 | R_F1_P_I_PARAM_SELECT, 0x05, /* low bit with 0xF0, (was 0x05) */ |
432 | R_F5_PULSGEN_LINE_LENGTH, 0xb0, | 422 | R_F5_PULSGEN_LINE_LENGTH, 0xb0, |
433 | R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG, 0x01, | 423 | R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG, 0x01, |
434 | 424 | ||
435 | R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x00, /* Disable I-port output */ | ||
436 | R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler (was 0xD0) */ | ||
437 | R_80_GLOBAL_CNTL_1, 0x20, /* Activate only task "B" */ | ||
438 | R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */ | ||
439 | R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* Enable I-port output */ | ||
440 | |||
441 | 0x00, 0x00 | 425 | 0x00, 0x00 |
442 | }; | 426 | }; |
443 | 427 | ||
@@ -466,7 +450,6 @@ static const unsigned char saa7115_cfg_vbi_off[] = { | |||
466 | 450 | ||
467 | static const unsigned char saa7115_init_misc[] = { | 451 | static const unsigned char saa7115_init_misc[] = { |
468 | R_81_V_SYNC_FLD_ID_SRC_SEL_AND_RETIMED_V_F, 0x01, | 452 | R_81_V_SYNC_FLD_ID_SRC_SEL_AND_RETIMED_V_F, 0x01, |
469 | 0x82, 0x00, /* Reserved register - value should be zero*/ | ||
470 | R_83_X_PORT_I_O_ENA_AND_OUT_CLK, 0x01, | 453 | R_83_X_PORT_I_O_ENA_AND_OUT_CLK, 0x01, |
471 | R_84_I_PORT_SIGNAL_DEF, 0x20, | 454 | R_84_I_PORT_SIGNAL_DEF, 0x20, |
472 | R_85_I_PORT_SIGNAL_POLAR, 0x21, | 455 | R_85_I_PORT_SIGNAL_POLAR, 0x21, |
@@ -823,6 +806,112 @@ static int saa711x_get_v4lctrl(struct i2c_client *client, struct v4l2_control *c | |||
823 | return 0; | 806 | return 0; |
824 | } | 807 | } |
825 | 808 | ||
809 | static int saa711x_set_size(struct i2c_client *client, int width, int height) | ||
810 | { | ||
811 | struct saa711x_state *state = i2c_get_clientdata(client); | ||
812 | int HPSC, HFSC; | ||
813 | int VSCY; | ||
814 | int res; | ||
815 | int is_50hz = state->std & V4L2_STD_625_50; | ||
816 | int Vsrc = is_50hz ? 576 : 480; | ||
817 | |||
818 | v4l_dbg(1, debug, client, "decoder set size to %ix%i\n",width,height); | ||
819 | |||
820 | /* FIXME need better bounds checking here */ | ||
821 | if ((width < 1) || (width > 1440)) | ||
822 | return -EINVAL; | ||
823 | if ((height < 1) || (height > Vsrc)) | ||
824 | return -EINVAL; | ||
825 | |||
826 | if (!saa711x_has_reg(state->ident,R_D0_B_HORIZ_PRESCALING)) { | ||
827 | /* Decoder only supports 720 columns and 480 or 576 lines */ | ||
828 | if (width != 720) | ||
829 | return -EINVAL; | ||
830 | if (height != Vsrc) | ||
831 | return -EINVAL; | ||
832 | } | ||
833 | |||
834 | state->width = width; | ||
835 | state->height = height; | ||
836 | |||
837 | if (!saa711x_has_reg(state->ident, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH)) | ||
838 | return 0; | ||
839 | |||
840 | /* probably have a valid size, let's set it */ | ||
841 | /* Set output width/height */ | ||
842 | /* width */ | ||
843 | |||
844 | saa711x_write(client, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, | ||
845 | (u8) (width & 0xff)); | ||
846 | saa711x_write(client, R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, | ||
847 | (u8) ((width >> 8) & 0xff)); | ||
848 | |||
849 | /* Vertical Scaling uses height/2 */ | ||
850 | res=height/2; | ||
851 | |||
852 | /* On 60Hz, it is using a higher Vertical Output Size */ | ||
853 | if (!is_50hz) | ||
854 | res+=(480-HRES_60HZ)>>1; | ||
855 | |||
856 | /* height */ | ||
857 | saa711x_write(client, R_CE_B_VERT_OUTPUT_WINDOW_LENGTH, | ||
858 | (u8) (res & 0xff)); | ||
859 | saa711x_write(client, R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB, | ||
860 | (u8) ((res >> 8) & 0xff)); | ||
861 | |||
862 | /* Scaling settings */ | ||
863 | /* Hprescaler is floor(inres/outres) */ | ||
864 | HPSC = (int)(720 / width); | ||
865 | /* 0 is not allowed (div. by zero) */ | ||
866 | HPSC = HPSC ? HPSC : 1; | ||
867 | HFSC = (int)((1024 * 720) / (HPSC * width)); | ||
868 | /* FIXME hardcodes to "Task B" | ||
869 | * write H prescaler integer */ | ||
870 | saa711x_write(client, R_D0_B_HORIZ_PRESCALING, | ||
871 | (u8) (HPSC & 0x3f)); | ||
872 | |||
873 | v4l_dbg(1, debug, client, "Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC); | ||
874 | /* write H fine-scaling (luminance) */ | ||
875 | saa711x_write(client, R_D8_B_HORIZ_LUMA_SCALING_INC, | ||
876 | (u8) (HFSC & 0xff)); | ||
877 | saa711x_write(client, R_D9_B_HORIZ_LUMA_SCALING_INC_MSB, | ||
878 | (u8) ((HFSC >> 8) & 0xff)); | ||
879 | /* write H fine-scaling (chrominance) | ||
880 | * must be lum/2, so i'll just bitshift :) */ | ||
881 | saa711x_write(client, R_DC_B_HORIZ_CHROMA_SCALING, | ||
882 | (u8) ((HFSC >> 1) & 0xff)); | ||
883 | saa711x_write(client, R_DD_B_HORIZ_CHROMA_SCALING_MSB, | ||
884 | (u8) ((HFSC >> 9) & 0xff)); | ||
885 | |||
886 | VSCY = (int)((1024 * Vsrc) / height); | ||
887 | v4l_dbg(1, debug, client, "Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY); | ||
888 | |||
889 | /* Correct Contrast and Luminance */ | ||
890 | saa711x_write(client, R_D5_B_LUMA_CONTRAST_CNTL, | ||
891 | (u8) (64 * 1024 / VSCY)); | ||
892 | saa711x_write(client, R_D6_B_CHROMA_SATURATION_CNTL, | ||
893 | (u8) (64 * 1024 / VSCY)); | ||
894 | |||
895 | /* write V fine-scaling (luminance) */ | ||
896 | saa711x_write(client, R_E0_B_VERT_LUMA_SCALING_INC, | ||
897 | (u8) (VSCY & 0xff)); | ||
898 | saa711x_write(client, R_E1_B_VERT_LUMA_SCALING_INC_MSB, | ||
899 | (u8) ((VSCY >> 8) & 0xff)); | ||
900 | /* write V fine-scaling (chrominance) */ | ||
901 | saa711x_write(client, R_E2_B_VERT_CHROMA_SCALING_INC, | ||
902 | (u8) (VSCY & 0xff)); | ||
903 | saa711x_write(client, R_E3_B_VERT_CHROMA_SCALING_INC_MSB, | ||
904 | (u8) ((VSCY >> 8) & 0xff)); | ||
905 | |||
906 | saa711x_writeregs(client, saa7115_cfg_reset_scaler); | ||
907 | |||
908 | /* Activates task "B" */ | ||
909 | saa711x_write(client, R_80_GLOBAL_CNTL_1, | ||
910 | saa711x_read(client,R_80_GLOBAL_CNTL_1)|0x20); | ||
911 | |||
912 | return 0; | ||
913 | } | ||
914 | |||
826 | static void saa711x_set_v4lstd(struct i2c_client *client, v4l2_std_id std) | 915 | static void saa711x_set_v4lstd(struct i2c_client *client, v4l2_std_id std) |
827 | { | 916 | { |
828 | struct saa711x_state *state = i2c_get_clientdata(client); | 917 | struct saa711x_state *state = i2c_get_clientdata(client); |
@@ -837,13 +926,17 @@ static void saa711x_set_v4lstd(struct i2c_client *client, v4l2_std_id std) | |||
837 | if (std == state->std) | 926 | if (std == state->std) |
838 | return; | 927 | return; |
839 | 928 | ||
929 | state->std = std; | ||
930 | |||
840 | // This works for NTSC-M, SECAM-L and the 50Hz PAL variants. | 931 | // This works for NTSC-M, SECAM-L and the 50Hz PAL variants. |
841 | if (std & V4L2_STD_525_60) { | 932 | if (std & V4L2_STD_525_60) { |
842 | v4l_dbg(1, debug, client, "decoder set standard 60 Hz\n"); | 933 | v4l_dbg(1, debug, client, "decoder set standard 60 Hz\n"); |
843 | saa711x_writeregs(client, saa7115_cfg_60hz_video); | 934 | saa711x_writeregs(client, saa7115_cfg_60hz_video); |
935 | saa711x_set_size(client,720,480); | ||
844 | } else { | 936 | } else { |
845 | v4l_dbg(1, debug, client, "decoder set standard 50 Hz\n"); | 937 | v4l_dbg(1, debug, client, "decoder set standard 50 Hz\n"); |
846 | saa711x_writeregs(client, saa7115_cfg_50hz_video); | 938 | saa711x_writeregs(client, saa7115_cfg_50hz_video); |
939 | saa711x_set_size(client,720,576); | ||
847 | } | 940 | } |
848 | 941 | ||
849 | /* Register 0E - Bits D6-D4 on NO-AUTO mode | 942 | /* Register 0E - Bits D6-D4 on NO-AUTO mode |
@@ -855,8 +948,6 @@ static void saa711x_set_v4lstd(struct i2c_client *client, v4l2_std_id std) | |||
855 | 011 NTSC N (3.58MHz) PAL M (3.58MHz) | 948 | 011 NTSC N (3.58MHz) PAL M (3.58MHz) |
856 | 100 reserved NTSC-Japan (3.58MHz) | 949 | 100 reserved NTSC-Japan (3.58MHz) |
857 | */ | 950 | */ |
858 | state->std = std; | ||
859 | |||
860 | if (state->ident == V4L2_IDENT_SAA7111 || | 951 | if (state->ident == V4L2_IDENT_SAA7111 || |
861 | state->ident == V4L2_IDENT_SAA7113) { | 952 | state->ident == V4L2_IDENT_SAA7113) { |
862 | u8 reg = saa711x_read(client, R_0E_CHROMA_CNTL_1) & 0x8f; | 953 | u8 reg = saa711x_read(client, R_0E_CHROMA_CNTL_1) & 0x8f; |
@@ -937,6 +1028,7 @@ static void saa711x_log_status(struct i2c_client *client) | |||
937 | v4l_info(client, "Detected format: BW/No color\n"); | 1028 | v4l_info(client, "Detected format: BW/No color\n"); |
938 | break; | 1029 | break; |
939 | } | 1030 | } |
1031 | v4l_info(client, "Width, Height: %d, %d\n", state->width, state->height); | ||
940 | } | 1032 | } |
941 | 1033 | ||
942 | /* setup the sliced VBI lcr registers according to the sliced VBI format */ | 1034 | /* setup the sliced VBI lcr registers according to the sliced VBI format */ |
@@ -1051,100 +1143,6 @@ static int saa711x_get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt | |||
1051 | return 0; | 1143 | return 0; |
1052 | } | 1144 | } |
1053 | 1145 | ||
1054 | static int saa711x_set_size(struct i2c_client *client, int width, int height) | ||
1055 | { | ||
1056 | struct saa711x_state *state = i2c_get_clientdata(client); | ||
1057 | int HPSC, HFSC; | ||
1058 | int VSCY; | ||
1059 | int res; | ||
1060 | int is_50hz = state->std & V4L2_STD_625_50; | ||
1061 | int Vsrc = is_50hz ? 576 : 480+16; | ||
1062 | |||
1063 | v4l_dbg(1, debug, client, "decoder set size to %ix%i\n",width,height); | ||
1064 | |||
1065 | /* FIXME need better bounds checking here */ | ||
1066 | if ((width < 1) || (width > 1440)) | ||
1067 | return -EINVAL; | ||
1068 | if ((height < 1) || (height > 960)) | ||
1069 | return -EINVAL; | ||
1070 | |||
1071 | if (!saa711x_has_reg(state->ident,R_D0_B_HORIZ_PRESCALING)) { | ||
1072 | /* Decoder only supports 720 columns and 480 or 576 lines */ | ||
1073 | if (width != 720) | ||
1074 | return -EINVAL; | ||
1075 | if (height != Vsrc) | ||
1076 | return -EINVAL; | ||
1077 | } | ||
1078 | if (!saa711x_has_reg(state->ident,R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH)) | ||
1079 | return 0; | ||
1080 | |||
1081 | /* probably have a valid size, let's set it */ | ||
1082 | /* Set output width/height */ | ||
1083 | /* width */ | ||
1084 | |||
1085 | saa711x_write(client, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, | ||
1086 | (u8) (width & 0xff)); | ||
1087 | saa711x_write(client, R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, | ||
1088 | (u8) ((width >> 8) & 0xff)); | ||
1089 | |||
1090 | /* Vertical Scaling uses height/2 */ | ||
1091 | res=height/2; | ||
1092 | |||
1093 | /* height */ | ||
1094 | saa711x_write(client, R_CE_B_VERT_OUTPUT_WINDOW_LENGTH, | ||
1095 | (u8) (res & 0xff)); | ||
1096 | saa711x_write(client, R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB, | ||
1097 | (u8) ((res >> 8) & 0xff)); | ||
1098 | |||
1099 | /* Scaling settings */ | ||
1100 | /* Hprescaler is floor(inres/outres) */ | ||
1101 | HPSC = (int)(720 / width); | ||
1102 | /* 0 is not allowed (div. by zero) */ | ||
1103 | HPSC = HPSC ? HPSC : 1; | ||
1104 | HFSC = (int)((1024 * 720) / (HPSC * width)); | ||
1105 | /* FIXME hardcodes to "Task B" | ||
1106 | * write H prescaler integer */ | ||
1107 | saa711x_write(client, R_D0_B_HORIZ_PRESCALING, | ||
1108 | (u8) (HPSC & 0x3f)); | ||
1109 | |||
1110 | v4l_dbg(1, debug, client, "Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC); | ||
1111 | /* write H fine-scaling (luminance) */ | ||
1112 | saa711x_write(client, R_D8_B_HORIZ_LUMA_SCALING_INC, | ||
1113 | (u8) (HFSC & 0xff)); | ||
1114 | saa711x_write(client, R_D9_B_HORIZ_LUMA_SCALING_INC_MSB, | ||
1115 | (u8) ((HFSC >> 8) & 0xff)); | ||
1116 | /* write H fine-scaling (chrominance) | ||
1117 | * must be lum/2, so i'll just bitshift :) */ | ||
1118 | saa711x_write(client, R_DC_B_HORIZ_CHROMA_SCALING, | ||
1119 | (u8) ((HFSC >> 1) & 0xff)); | ||
1120 | saa711x_write(client, R_DD_B_HORIZ_CHROMA_SCALING_MSB, | ||
1121 | (u8) ((HFSC >> 9) & 0xff)); | ||
1122 | |||
1123 | VSCY = (int)((1024 * Vsrc) / height); | ||
1124 | v4l_dbg(1, debug, client, "Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY); | ||
1125 | |||
1126 | /* Correct Contrast and Luminance */ | ||
1127 | saa711x_write(client, R_D5_B_LUMA_CONTRAST_CNTL, | ||
1128 | (u8) (64 * 1024 / VSCY)); | ||
1129 | saa711x_write(client, R_D6_B_CHROMA_SATURATION_CNTL, | ||
1130 | (u8) (64 * 1024 / VSCY)); | ||
1131 | |||
1132 | /* write V fine-scaling (luminance) */ | ||
1133 | saa711x_write(client, R_E0_B_VERT_LUMA_SCALING_INC, | ||
1134 | (u8) (VSCY & 0xff)); | ||
1135 | saa711x_write(client, R_E1_B_VERT_LUMA_SCALING_INC_MSB, | ||
1136 | (u8) ((VSCY >> 8) & 0xff)); | ||
1137 | /* write V fine-scaling (chrominance) */ | ||
1138 | saa711x_write(client, R_E2_B_VERT_CHROMA_SCALING_INC, | ||
1139 | (u8) (VSCY & 0xff)); | ||
1140 | saa711x_write(client, R_E3_B_VERT_CHROMA_SCALING_INC_MSB, | ||
1141 | (u8) ((VSCY >> 8) & 0xff)); | ||
1142 | |||
1143 | saa711x_writeregs(client, saa7115_cfg_reset_scaler); | ||
1144 | |||
1145 | return 0; | ||
1146 | } | ||
1147 | |||
1148 | static int saa711x_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt) | 1146 | static int saa711x_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt) |
1149 | { | 1147 | { |
1150 | if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) { | 1148 | if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) { |
@@ -1529,11 +1527,7 @@ static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind) | |||
1529 | saa711x_writeregs(client, saa7115_init_auto_input); | 1527 | saa711x_writeregs(client, saa7115_init_auto_input); |
1530 | } | 1528 | } |
1531 | saa711x_writeregs(client, saa7115_init_misc); | 1529 | saa711x_writeregs(client, saa7115_init_misc); |
1532 | state->std = V4L2_STD_NTSC; | 1530 | saa711x_set_v4lstd(client, V4L2_STD_NTSC); |
1533 | saa711x_set_size(client, 720, 480); | ||
1534 | saa711x_writeregs(client, saa7115_cfg_60hz_video); | ||
1535 | saa711x_set_audio_clock_freq(client, state->audclk_freq); | ||
1536 | saa711x_writeregs(client, saa7115_cfg_reset_scaler); | ||
1537 | 1531 | ||
1538 | i2c_attach_client(client); | 1532 | i2c_attach_client(client); |
1539 | 1533 | ||