diff options
Diffstat (limited to 'drivers/media/video/cx18/cx18-av-core.c')
-rw-r--r-- | drivers/media/video/cx18/cx18-av-core.c | 154 |
1 files changed, 109 insertions, 45 deletions
diff --git a/drivers/media/video/cx18/cx18-av-core.c b/drivers/media/video/cx18/cx18-av-core.c index 66864904c99b..faca43eb940f 100644 --- a/drivers/media/video/cx18/cx18-av-core.c +++ b/drivers/media/video/cx18/cx18-av-core.c | |||
@@ -69,6 +69,58 @@ int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 and_mask, | |||
69 | or_value); | 69 | or_value); |
70 | } | 70 | } |
71 | 71 | ||
72 | int cx18_av_write_no_acfg(struct cx18 *cx, u16 addr, u8 value, int no_acfg_mask) | ||
73 | { | ||
74 | int retval; | ||
75 | u32 saved_reg[8] = {0}; | ||
76 | |||
77 | if (no_acfg_mask & CXADEC_NO_ACFG_AFE) { | ||
78 | saved_reg[0] = cx18_av_read4(cx, CXADEC_CHIP_CTRL); | ||
79 | saved_reg[1] = cx18_av_read4(cx, CXADEC_AFE_CTRL); | ||
80 | } | ||
81 | |||
82 | if (no_acfg_mask & CXADEC_NO_ACFG_PLL) { | ||
83 | saved_reg[2] = cx18_av_read4(cx, CXADEC_PLL_CTRL1); | ||
84 | saved_reg[3] = cx18_av_read4(cx, CXADEC_VID_PLL_FRAC); | ||
85 | } | ||
86 | |||
87 | if (no_acfg_mask & CXADEC_NO_ACFG_VID) { | ||
88 | saved_reg[4] = cx18_av_read4(cx, CXADEC_HORIZ_TIM_CTRL); | ||
89 | saved_reg[5] = cx18_av_read4(cx, CXADEC_VERT_TIM_CTRL); | ||
90 | saved_reg[6] = cx18_av_read4(cx, CXADEC_SRC_COMB_CFG); | ||
91 | saved_reg[7] = cx18_av_read4(cx, CXADEC_CHROMA_VBIOFF_CFG); | ||
92 | } | ||
93 | |||
94 | retval = cx18_av_write(cx, addr, value); | ||
95 | |||
96 | if (no_acfg_mask & CXADEC_NO_ACFG_AFE) { | ||
97 | cx18_av_write4(cx, CXADEC_CHIP_CTRL, saved_reg[0]); | ||
98 | cx18_av_write4(cx, CXADEC_AFE_CTRL, saved_reg[1]); | ||
99 | } | ||
100 | |||
101 | if (no_acfg_mask & CXADEC_NO_ACFG_PLL) { | ||
102 | cx18_av_write4(cx, CXADEC_PLL_CTRL1, saved_reg[2]); | ||
103 | cx18_av_write4(cx, CXADEC_VID_PLL_FRAC, saved_reg[3]); | ||
104 | } | ||
105 | |||
106 | if (no_acfg_mask & CXADEC_NO_ACFG_VID) { | ||
107 | cx18_av_write4(cx, CXADEC_HORIZ_TIM_CTRL, saved_reg[4]); | ||
108 | cx18_av_write4(cx, CXADEC_VERT_TIM_CTRL, saved_reg[5]); | ||
109 | cx18_av_write4(cx, CXADEC_SRC_COMB_CFG, saved_reg[6]); | ||
110 | cx18_av_write4(cx, CXADEC_CHROMA_VBIOFF_CFG, saved_reg[7]); | ||
111 | } | ||
112 | |||
113 | return retval; | ||
114 | } | ||
115 | |||
116 | int cx18_av_and_or_no_acfg(struct cx18 *cx, u16 addr, unsigned and_mask, | ||
117 | u8 or_value, int no_acfg_mask) | ||
118 | { | ||
119 | return cx18_av_write_no_acfg(cx, addr, | ||
120 | (cx18_av_read(cx, addr) & and_mask) | | ||
121 | or_value, no_acfg_mask); | ||
122 | } | ||
123 | |||
72 | /* ----------------------------------------------------------------------- */ | 124 | /* ----------------------------------------------------------------------- */ |
73 | 125 | ||
74 | static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input, | 126 | static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input, |
@@ -170,26 +222,30 @@ static void input_change(struct cx18 *cx) | |||
170 | 222 | ||
171 | /* Follow step 8c and 8d of section 3.16 in the cx18_av datasheet */ | 223 | /* Follow step 8c and 8d of section 3.16 in the cx18_av datasheet */ |
172 | if (std & V4L2_STD_SECAM) | 224 | if (std & V4L2_STD_SECAM) |
173 | cx18_av_write(cx, 0x402, 0); | 225 | cx18_av_write_no_acfg(cx, 0x402, 0, CXADEC_NO_ACFG_ALL); |
174 | else { | 226 | else { |
175 | cx18_av_write(cx, 0x402, 0x04); | 227 | cx18_av_write_no_acfg(cx, 0x402, 0x04, CXADEC_NO_ACFG_ALL); |
176 | cx18_av_write(cx, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11); | 228 | cx18_av_write(cx, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11); |
177 | } | 229 | } |
178 | cx18_av_and_or(cx, 0x401, ~0x60, 0); | 230 | cx18_av_and_or_no_acfg(cx, 0x401, ~0x60, 0, |
179 | cx18_av_and_or(cx, 0x401, ~0x60, 0x60); | 231 | CXADEC_NO_ACFG_PLL | CXADEC_NO_ACFG_VID); |
232 | cx18_av_and_or_no_acfg(cx, 0x401, ~0x60, 0x60, | ||
233 | CXADEC_NO_ACFG_PLL | CXADEC_NO_ACFG_VID); | ||
180 | 234 | ||
181 | if (std & V4L2_STD_525_60) { | 235 | if (std & V4L2_STD_525_60) { |
182 | if (std == V4L2_STD_NTSC_M_JP) { | 236 | if (std == V4L2_STD_NTSC_M_JP) { |
183 | /* Japan uses EIAJ audio standard */ | 237 | /* Japan uses EIAJ audio standard */ |
184 | cx18_av_write(cx, 0x808, 0xf7); | 238 | cx18_av_write(cx, 0x808, 0xf7); |
239 | cx18_av_write(cx, 0x80b, 0x02); | ||
185 | } else if (std == V4L2_STD_NTSC_M_KR) { | 240 | } else if (std == V4L2_STD_NTSC_M_KR) { |
186 | /* South Korea uses A2 audio standard */ | 241 | /* South Korea uses A2 audio standard */ |
187 | cx18_av_write(cx, 0x808, 0xf8); | 242 | cx18_av_write(cx, 0x808, 0xf8); |
243 | cx18_av_write(cx, 0x80b, 0x03); | ||
188 | } else { | 244 | } else { |
189 | /* Others use the BTSC audio standard */ | 245 | /* Others use the BTSC audio standard */ |
190 | cx18_av_write(cx, 0x808, 0xf6); | 246 | cx18_av_write(cx, 0x808, 0xf6); |
247 | cx18_av_write(cx, 0x80b, 0x01); | ||
191 | } | 248 | } |
192 | cx18_av_write(cx, 0x80b, 0x00); | ||
193 | } else if (std & V4L2_STD_PAL) { | 249 | } else if (std & V4L2_STD_PAL) { |
194 | /* Follow tuner change procedure for PAL */ | 250 | /* Follow tuner change procedure for PAL */ |
195 | cx18_av_write(cx, 0x808, 0xff); | 251 | cx18_av_write(cx, 0x808, 0xff); |
@@ -226,7 +282,7 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input, | |||
226 | 282 | ||
227 | if ((vid_input & ~0xff0) || | 283 | if ((vid_input & ~0xff0) || |
228 | luma < CX18_AV_SVIDEO_LUMA1 || | 284 | luma < CX18_AV_SVIDEO_LUMA1 || |
229 | luma > CX18_AV_SVIDEO_LUMA4 || | 285 | luma > CX18_AV_SVIDEO_LUMA8 || |
230 | chroma < CX18_AV_SVIDEO_CHROMA4 || | 286 | chroma < CX18_AV_SVIDEO_CHROMA4 || |
231 | chroma > CX18_AV_SVIDEO_CHROMA8) { | 287 | chroma > CX18_AV_SVIDEO_CHROMA8) { |
232 | CX18_ERR("0x%04x is not a valid video input!\n", | 288 | CX18_ERR("0x%04x is not a valid video input!\n", |
@@ -260,7 +316,8 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input, | |||
260 | 316 | ||
261 | cx18_av_write(cx, 0x103, reg); | 317 | cx18_av_write(cx, 0x103, reg); |
262 | /* Set INPUT_MODE to Composite (0) or S-Video (1) */ | 318 | /* Set INPUT_MODE to Composite (0) or S-Video (1) */ |
263 | cx18_av_and_or(cx, 0x401, ~0x6, is_composite ? 0 : 0x02); | 319 | cx18_av_and_or_no_acfg(cx, 0x401, ~0x6, is_composite ? 0 : 0x02, |
320 | CXADEC_NO_ACFG_PLL | CXADEC_NO_ACFG_VID); | ||
264 | /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */ | 321 | /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */ |
265 | cx18_av_and_or(cx, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0); | 322 | cx18_av_and_or(cx, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0); |
266 | /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */ | 323 | /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */ |
@@ -316,12 +373,12 @@ static int set_v4lstd(struct cx18 *cx) | |||
316 | This happens for example with the Yuan MPC622. */ | 373 | This happens for example with the Yuan MPC622. */ |
317 | if (fmt >= 4 && fmt < 8) { | 374 | if (fmt >= 4 && fmt < 8) { |
318 | /* Set format to NTSC-M */ | 375 | /* Set format to NTSC-M */ |
319 | cx18_av_and_or(cx, 0x400, ~0xf, 1); | 376 | cx18_av_and_or_no_acfg(cx, 0x400, ~0xf, 1, CXADEC_NO_ACFG_AFE); |
320 | /* Turn off LCOMB */ | 377 | /* Turn off LCOMB */ |
321 | cx18_av_and_or(cx, 0x47b, ~6, 0); | 378 | cx18_av_and_or(cx, 0x47b, ~6, 0); |
322 | } | 379 | } |
323 | cx18_av_and_or(cx, 0x400, ~0xf, fmt); | 380 | cx18_av_and_or_no_acfg(cx, 0x400, ~0xf, fmt, CXADEC_NO_ACFG_AFE); |
324 | cx18_av_and_or(cx, 0x403, ~0x3, pal_m); | 381 | cx18_av_and_or_no_acfg(cx, 0x403, ~0x3, pal_m, CXADEC_NO_ACFG_ALL); |
325 | cx18_av_vbi_setup(cx); | 382 | cx18_av_vbi_setup(cx); |
326 | input_change(cx); | 383 | input_change(cx); |
327 | return 0; | 384 | return 0; |
@@ -741,8 +798,8 @@ static void log_audio_status(struct cx18 *cx) | |||
741 | { | 798 | { |
742 | struct cx18_av_state *state = &cx->av_state; | 799 | struct cx18_av_state *state = &cx->av_state; |
743 | u8 download_ctl = cx18_av_read(cx, 0x803); | 800 | u8 download_ctl = cx18_av_read(cx, 0x803); |
744 | u8 mod_det_stat0 = cx18_av_read(cx, 0x805); | 801 | u8 mod_det_stat0 = cx18_av_read(cx, 0x804); |
745 | u8 mod_det_stat1 = cx18_av_read(cx, 0x804); | 802 | u8 mod_det_stat1 = cx18_av_read(cx, 0x805); |
746 | u8 audio_config = cx18_av_read(cx, 0x808); | 803 | u8 audio_config = cx18_av_read(cx, 0x808); |
747 | u8 pref_mode = cx18_av_read(cx, 0x809); | 804 | u8 pref_mode = cx18_av_read(cx, 0x809); |
748 | u8 afc0 = cx18_av_read(cx, 0x80b); | 805 | u8 afc0 = cx18_av_read(cx, 0x80b); |
@@ -760,12 +817,12 @@ static void log_audio_status(struct cx18 *cx) | |||
760 | case 0x12: p = "dual with SAP"; break; | 817 | case 0x12: p = "dual with SAP"; break; |
761 | case 0x14: p = "tri with SAP"; break; | 818 | case 0x14: p = "tri with SAP"; break; |
762 | case 0xfe: p = "forced mode"; break; | 819 | case 0xfe: p = "forced mode"; break; |
763 | default: p = "not defined"; | 820 | default: p = "not defined"; break; |
764 | } | 821 | } |
765 | CX18_INFO("Detected audio mode: %s\n", p); | 822 | CX18_INFO("Detected audio mode: %s\n", p); |
766 | 823 | ||
767 | switch (mod_det_stat1) { | 824 | switch (mod_det_stat1) { |
768 | case 0x00: p = "BTSC"; break; | 825 | case 0x00: p = "not defined"; break; |
769 | case 0x01: p = "EIAJ"; break; | 826 | case 0x01: p = "EIAJ"; break; |
770 | case 0x02: p = "A2-M"; break; | 827 | case 0x02: p = "A2-M"; break; |
771 | case 0x03: p = "A2-BG"; break; | 828 | case 0x03: p = "A2-BG"; break; |
@@ -779,8 +836,13 @@ static void log_audio_status(struct cx18 *cx) | |||
779 | case 0x0b: p = "NICAM-I"; break; | 836 | case 0x0b: p = "NICAM-I"; break; |
780 | case 0x0c: p = "NICAM-L"; break; | 837 | case 0x0c: p = "NICAM-L"; break; |
781 | case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break; | 838 | case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break; |
839 | case 0x0e: p = "IF FM Radio"; break; | ||
840 | case 0x0f: p = "BTSC"; break; | ||
841 | case 0x10: p = "detected chrominance"; break; | ||
842 | case 0xfd: p = "unknown audio standard"; break; | ||
843 | case 0xfe: p = "forced audio standard"; break; | ||
782 | case 0xff: p = "no detected audio standard"; break; | 844 | case 0xff: p = "no detected audio standard"; break; |
783 | default: p = "not defined"; | 845 | default: p = "not defined"; break; |
784 | } | 846 | } |
785 | CX18_INFO("Detected audio standard: %s\n", p); | 847 | CX18_INFO("Detected audio standard: %s\n", p); |
786 | CX18_INFO("Audio muted: %s\n", | 848 | CX18_INFO("Audio muted: %s\n", |
@@ -789,22 +851,23 @@ static void log_audio_status(struct cx18 *cx) | |||
789 | (download_ctl & 0x10) ? "running" : "stopped"); | 851 | (download_ctl & 0x10) ? "running" : "stopped"); |
790 | 852 | ||
791 | switch (audio_config >> 4) { | 853 | switch (audio_config >> 4) { |
792 | case 0x00: p = "BTSC"; break; | 854 | case 0x00: p = "undefined"; break; |
793 | case 0x01: p = "EIAJ"; break; | 855 | case 0x01: p = "BTSC"; break; |
794 | case 0x02: p = "A2-M"; break; | 856 | case 0x02: p = "EIAJ"; break; |
795 | case 0x03: p = "A2-BG"; break; | 857 | case 0x03: p = "A2-M"; break; |
796 | case 0x04: p = "A2-DK1"; break; | 858 | case 0x04: p = "A2-BG"; break; |
797 | case 0x05: p = "A2-DK2"; break; | 859 | case 0x05: p = "A2-DK1"; break; |
798 | case 0x06: p = "A2-DK3"; break; | 860 | case 0x06: p = "A2-DK2"; break; |
799 | case 0x07: p = "A1 (6.0 MHz FM Mono)"; break; | 861 | case 0x07: p = "A2-DK3"; break; |
800 | case 0x08: p = "AM-L"; break; | 862 | case 0x08: p = "A1 (6.0 MHz FM Mono)"; break; |
801 | case 0x09: p = "NICAM-BG"; break; | 863 | case 0x09: p = "AM-L"; break; |
802 | case 0x0a: p = "NICAM-DK"; break; | 864 | case 0x0a: p = "NICAM-BG"; break; |
803 | case 0x0b: p = "NICAM-I"; break; | 865 | case 0x0b: p = "NICAM-DK"; break; |
804 | case 0x0c: p = "NICAM-L"; break; | 866 | case 0x0c: p = "NICAM-I"; break; |
805 | case 0x0d: p = "FM radio"; break; | 867 | case 0x0d: p = "NICAM-L"; break; |
868 | case 0x0e: p = "FM radio"; break; | ||
806 | case 0x0f: p = "automatic detection"; break; | 869 | case 0x0f: p = "automatic detection"; break; |
807 | default: p = "undefined"; | 870 | default: p = "undefined"; break; |
808 | } | 871 | } |
809 | CX18_INFO("Configured audio standard: %s\n", p); | 872 | CX18_INFO("Configured audio standard: %s\n", p); |
810 | 873 | ||
@@ -815,12 +878,9 @@ static void log_audio_status(struct cx18 *cx) | |||
815 | case 0x02: p = "MONO3 (STEREO forced MONO)"; break; | 878 | case 0x02: p = "MONO3 (STEREO forced MONO)"; break; |
816 | case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break; | 879 | case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break; |
817 | case 0x04: p = "STEREO"; break; | 880 | case 0x04: p = "STEREO"; break; |
818 | case 0x05: p = "DUAL1 (AB)"; break; | 881 | case 0x05: p = "DUAL1 (AC)"; break; |
819 | case 0x06: p = "DUAL2 (AC) (FM)"; break; | 882 | case 0x06: p = "DUAL2 (BC)"; break; |
820 | case 0x07: p = "DUAL3 (BC) (FM)"; break; | 883 | case 0x07: p = "DUAL3 (AB)"; break; |
821 | case 0x08: p = "DUAL4 (AC) (AM)"; break; | ||
822 | case 0x09: p = "DUAL5 (BC) (AM)"; break; | ||
823 | case 0x0a: p = "SAP"; break; | ||
824 | default: p = "undefined"; | 884 | default: p = "undefined"; |
825 | } | 885 | } |
826 | CX18_INFO("Configured audio mode: %s\n", p); | 886 | CX18_INFO("Configured audio mode: %s\n", p); |
@@ -835,9 +895,11 @@ static void log_audio_status(struct cx18 *cx) | |||
835 | case 0x06: p = "BTSC"; break; | 895 | case 0x06: p = "BTSC"; break; |
836 | case 0x07: p = "EIAJ"; break; | 896 | case 0x07: p = "EIAJ"; break; |
837 | case 0x08: p = "A2-M"; break; | 897 | case 0x08: p = "A2-M"; break; |
838 | case 0x09: p = "FM Radio"; break; | 898 | case 0x09: p = "FM Radio (4.5 MHz)"; break; |
899 | case 0x0a: p = "FM Radio (5.5 MHz)"; break; | ||
900 | case 0x0b: p = "S-Video"; break; | ||
839 | case 0x0f: p = "automatic standard and mode detection"; break; | 901 | case 0x0f: p = "automatic standard and mode detection"; break; |
840 | default: p = "undefined"; | 902 | default: p = "undefined"; break; |
841 | } | 903 | } |
842 | CX18_INFO("Configured audio system: %s\n", p); | 904 | CX18_INFO("Configured audio system: %s\n", p); |
843 | } | 905 | } |
@@ -857,22 +919,24 @@ static void log_audio_status(struct cx18 *cx) | |||
857 | case 5: p = "language AC"; break; | 919 | case 5: p = "language AC"; break; |
858 | case 6: p = "language BC"; break; | 920 | case 6: p = "language BC"; break; |
859 | case 7: p = "language AB"; break; | 921 | case 7: p = "language AB"; break; |
860 | default: p = "undefined"; | 922 | default: p = "undefined"; break; |
861 | } | 923 | } |
862 | CX18_INFO("Preferred audio mode: %s\n", p); | 924 | CX18_INFO("Preferred audio mode: %s\n", p); |
863 | 925 | ||
864 | if ((audio_config & 0xf) == 0xf) { | 926 | if ((audio_config & 0xf) == 0xf) { |
865 | switch ((afc0 >> 2) & 0x1) { | 927 | switch ((afc0 >> 3) & 0x1) { |
866 | case 0: p = "system DK"; break; | 928 | case 0: p = "system DK"; break; |
867 | case 1: p = "system L"; break; | 929 | case 1: p = "system L"; break; |
868 | } | 930 | } |
869 | CX18_INFO("Selected 65 MHz format: %s\n", p); | 931 | CX18_INFO("Selected 65 MHz format: %s\n", p); |
870 | 932 | ||
871 | switch (afc0 & 0x3) { | 933 | switch (afc0 & 0x7) { |
872 | case 0: p = "BTSC"; break; | 934 | case 0: p = "Chroma"; break; |
873 | case 1: p = "EIAJ"; break; | 935 | case 1: p = "BTSC"; break; |
874 | case 2: p = "A2-M"; break; | 936 | case 2: p = "EIAJ"; break; |
875 | default: p = "undefined"; | 937 | case 3: p = "A2-M"; break; |
938 | case 4: p = "autodetect"; break; | ||
939 | default: p = "undefined"; break; | ||
876 | } | 940 | } |
877 | CX18_INFO("Selected 45 MHz format: %s\n", p); | 941 | CX18_INFO("Selected 45 MHz format: %s\n", p); |
878 | } | 942 | } |