diff options
author | Hans Verkuil <hverkuil@xs4all.nl> | 2006-03-19 06:21:56 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2006-03-24 14:26:57 -0500 |
commit | de533ccf8dd51f38ef3c1751f9eb5ad3f2fcfad9 (patch) | |
tree | a82aedd3ae45a9455c24cda20e51cd8e7596182f /drivers/media/video/msp3400-kthreads.c | |
parent | 9a80a93da738c631de644175fbd669ab9a9cb624 (diff) |
V4L/DVB (3580): Last round of msp3400 cleanups before adding routing commands
Lots of cleanups:
- remove duplicate actions
- add D/K3 Dual FM-Stereo and D/K NICAM FM (HDEV3) support
- put prescales in the proper place
- add missing D/K NICAM
- msp34xxg_reset now only resets instead of also starting the autodetect
(moved that to msp34xxg_thread)
- fix support for SAP.
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/msp3400-kthreads.c')
-rw-r--r-- | drivers/media/video/msp3400-kthreads.c | 188 |
1 files changed, 105 insertions, 83 deletions
diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c index 972f2c80dbe2..88b216cc49d7 100644 --- a/drivers/media/video/msp3400-kthreads.c +++ b/drivers/media/video/msp3400-kthreads.c | |||
@@ -44,11 +44,13 @@ static struct { | |||
44 | { 0x0004, MSP_CARRIER(6.5), MSP_CARRIER(6.2578125), "6.5/6.25 D/K1 Dual FM-Stereo" }, | 44 | { 0x0004, MSP_CARRIER(6.5), MSP_CARRIER(6.2578125), "6.5/6.25 D/K1 Dual FM-Stereo" }, |
45 | { 0x0005, MSP_CARRIER(6.5), MSP_CARRIER(6.7421875), "6.5/6.74 D/K2 Dual FM-Stereo" }, | 45 | { 0x0005, MSP_CARRIER(6.5), MSP_CARRIER(6.7421875), "6.5/6.74 D/K2 Dual FM-Stereo" }, |
46 | { 0x0006, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5 D/K FM-Mono (HDEV3)" }, | 46 | { 0x0006, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5 D/K FM-Mono (HDEV3)" }, |
47 | { 0x0007, MSP_CARRIER(6.5), MSP_CARRIER(5.7421875), "6.5/5.74 D/K3 Dual FM-Stereo" }, | ||
47 | { 0x0008, MSP_CARRIER(5.5), MSP_CARRIER(5.85), "5.5/5.85 B/G NICAM FM" }, | 48 | { 0x0008, MSP_CARRIER(5.5), MSP_CARRIER(5.85), "5.5/5.85 B/G NICAM FM" }, |
48 | { 0x0009, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 L NICAM AM" }, | 49 | { 0x0009, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 L NICAM AM" }, |
49 | { 0x000a, MSP_CARRIER(6.0), MSP_CARRIER(6.55), "6.0/6.55 I NICAM FM" }, | 50 | { 0x000a, MSP_CARRIER(6.0), MSP_CARRIER(6.55), "6.0/6.55 I NICAM FM" }, |
50 | { 0x000b, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM" }, | 51 | { 0x000b, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM" }, |
51 | { 0x000c, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM (HDEV2)" }, | 52 | { 0x000c, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM (HDEV2)" }, |
53 | { 0x000d, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM (HDEV3)" }, | ||
52 | { 0x0020, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M BTSC-Stereo" }, | 54 | { 0x0020, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M BTSC-Stereo" }, |
53 | { 0x0021, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M BTSC-Mono + SAP" }, | 55 | { 0x0021, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M BTSC-Mono + SAP" }, |
54 | { 0x0030, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M EIA-J Japan Stereo" }, | 56 | { 0x0030, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M EIA-J Japan Stereo" }, |
@@ -206,12 +208,13 @@ void msp3400c_set_mode(struct i2c_client *client, int mode) | |||
206 | msp3400c_set_carrier(client, data->cdo1, data->cdo2); | 208 | msp3400c_set_carrier(client, data->cdo1, data->cdo2); |
207 | 209 | ||
208 | msp_set_source(client, data->dsp_src); | 210 | msp_set_source(client, data->dsp_src); |
209 | msp_write_dsp(client, 0x000e, data->dsp_matrix); | 211 | /* set prescales */ |
210 | 212 | ||
211 | if (state->has_nicam) { | 213 | /* volume prescale for SCART (AM mono input) */ |
212 | /* nicam prescale */ | 214 | msp_write_dsp(client, 0x000d, 0x1900); |
213 | msp_write_dsp(client, 0x0010, 0x5a00); /* was: 0x3000 */ | 215 | msp_write_dsp(client, 0x000e, data->dsp_matrix); |
214 | } | 216 | if (state->has_nicam) /* nicam prescale */ |
217 | msp_write_dsp(client, 0x0010, 0x5a00); | ||
215 | } | 218 | } |
216 | 219 | ||
217 | /* Set audio mode. Note that the pre-'G' models do not support BTSC+SAP, | 220 | /* Set audio mode. Note that the pre-'G' models do not support BTSC+SAP, |
@@ -270,7 +273,6 @@ static void msp3400c_set_audmode(struct i2c_client *client) | |||
270 | case MSP_MODE_FM_NICAM2: | 273 | case MSP_MODE_FM_NICAM2: |
271 | case MSP_MODE_AM_NICAM: | 274 | case MSP_MODE_AM_NICAM: |
272 | v4l_dbg(1, msp_debug, client, "NICAM set_audmode: %s\n",modestr); | 275 | v4l_dbg(1, msp_debug, client, "NICAM set_audmode: %s\n",modestr); |
273 | msp3400c_set_carrier(client, state->second, state->main); | ||
274 | if (state->nicam_on) | 276 | if (state->nicam_on) |
275 | src = 0x0100; /* NICAM */ | 277 | src = 0x0100; /* NICAM */ |
276 | break; | 278 | break; |
@@ -426,8 +428,8 @@ static void watch_stereo(struct i2c_client *client) | |||
426 | { | 428 | { |
427 | struct msp_state *state = i2c_get_clientdata(client); | 429 | struct msp_state *state = i2c_get_clientdata(client); |
428 | 430 | ||
429 | if (msp3400c_detect_stereo(client)) { | 431 | if (msp_detect_stereo(client)) { |
430 | msp3400c_set_audmode(client); | 432 | msp_set_audmode(client); |
431 | } | 433 | } |
432 | 434 | ||
433 | if (msp_once) | 435 | if (msp_once) |
@@ -463,7 +465,7 @@ int msp3400c_thread(void *data) | |||
463 | 465 | ||
464 | /* mute */ | 466 | /* mute */ |
465 | msp_set_mute(client); | 467 | msp_set_mute(client); |
466 | msp3400c_set_mode(client, MSP_MODE_AM_DETECT /* +1 */ ); | 468 | msp3400c_set_mode(client, MSP_MODE_AM_DETECT); |
467 | val1 = val2 = 0; | 469 | val1 = val2 = 0; |
468 | max1 = max2 = -1; | 470 | max1 = max2 = -1; |
469 | state->watch_stereo = 0; | 471 | state->watch_stereo = 0; |
@@ -571,8 +573,6 @@ int msp3400c_thread(void *data) | |||
571 | state->second = msp3400c_carrier_detect_65[max2].cdo; | 573 | state->second = msp3400c_carrier_detect_65[max2].cdo; |
572 | msp3400c_set_mode(client, MSP_MODE_AM_NICAM); | 574 | msp3400c_set_mode(client, MSP_MODE_AM_NICAM); |
573 | msp3400c_set_carrier(client, state->second, state->main); | 575 | msp3400c_set_carrier(client, state->second, state->main); |
574 | /* volume prescale for SCART (AM mono input) */ | ||
575 | msp_write_dsp(client, 0x000d, 0x1900); | ||
576 | state->watch_stereo = 1; | 576 | state->watch_stereo = 1; |
577 | } else if (max2 == 0 && state->has_nicam) { | 577 | } else if (max2 == 0 && state->has_nicam) { |
578 | /* D/K NICAM */ | 578 | /* D/K NICAM */ |
@@ -650,7 +650,8 @@ int msp3410d_thread(void *data) | |||
650 | if (msp_sleep(state,200)) | 650 | if (msp_sleep(state,200)) |
651 | goto restart; | 651 | goto restart; |
652 | 652 | ||
653 | /* start autodetect */ | 653 | /* start autodetect. Note: autodetect is not supported for |
654 | NTSC-M and radio, hence we force the standard in those cases. */ | ||
654 | if (state->radio) | 655 | if (state->radio) |
655 | std = 0x40; | 656 | std = 0x40; |
656 | else | 657 | else |
@@ -694,23 +695,19 @@ int msp3410d_thread(void *data) | |||
694 | v4l_dbg(1, msp_debug, client, "autodetection failed," | 695 | v4l_dbg(1, msp_debug, client, "autodetection failed," |
695 | " switching to backup standard: %s (0x%04x)\n", | 696 | " switching to backup standard: %s (0x%04x)\n", |
696 | msp_stdlist[8].name ? msp_stdlist[8].name : "unknown",val); | 697 | msp_stdlist[8].name ? msp_stdlist[8].name : "unknown",val); |
697 | val = 0x0009; | 698 | state->std = val = 0x0009; |
698 | msp_write_dem(client, 0x20, val); | 699 | msp_write_dem(client, 0x20, val); |
699 | } | 700 | } |
700 | 701 | ||
701 | /* set various prescales */ | ||
702 | msp_write_dsp(client, 0x0d, 0x1900); /* scart */ | ||
703 | msp_write_dsp(client, 0x0e, 0x2403); /* FM */ | ||
704 | msp_write_dsp(client, 0x10, 0x5a00); /* nicam */ | ||
705 | |||
706 | /* set stereo */ | 702 | /* set stereo */ |
707 | switch (val) { | 703 | switch (val) { |
708 | case 0x0008: /* B/G NICAM */ | 704 | case 0x0008: /* B/G NICAM */ |
709 | case 0x000a: /* I NICAM */ | 705 | case 0x000a: /* I NICAM */ |
710 | if (val == 0x0008) | 706 | case 0x000b: /* D/K NICAM */ |
711 | state->mode = MSP_MODE_FM_NICAM1; | 707 | if (val == 0x000a) |
712 | else | ||
713 | state->mode = MSP_MODE_FM_NICAM2; | 708 | state->mode = MSP_MODE_FM_NICAM2; |
709 | else | ||
710 | state->mode = MSP_MODE_FM_NICAM1; | ||
714 | /* just turn on stereo */ | 711 | /* just turn on stereo */ |
715 | state->rxsubchans = V4L2_TUNER_SUB_STEREO; | 712 | state->rxsubchans = V4L2_TUNER_SUB_STEREO; |
716 | state->nicam_on = 1; | 713 | state->nicam_on = 1; |
@@ -738,6 +735,7 @@ int msp3410d_thread(void *data) | |||
738 | /* scart routing (this doesn't belong here I think) */ | 735 | /* scart routing (this doesn't belong here I think) */ |
739 | msp_set_scart(client,SCART_IN2,0); | 736 | msp_set_scart(client,SCART_IN2,0); |
740 | break; | 737 | break; |
738 | case 0x0002: | ||
741 | case 0x0003: | 739 | case 0x0003: |
742 | case 0x0004: | 740 | case 0x0004: |
743 | case 0x0005: | 741 | case 0x0005: |
@@ -747,12 +745,19 @@ int msp3410d_thread(void *data) | |||
747 | break; | 745 | break; |
748 | } | 746 | } |
749 | 747 | ||
750 | /* unmute, restore misc registers */ | 748 | /* set various prescales */ |
751 | msp_set_audio(client); | 749 | msp_write_dsp(client, 0x0d, 0x1900); /* scart */ |
752 | msp_write_dsp(client, 0x13, state->acb); | 750 | msp_write_dsp(client, 0x0e, 0x3000); /* FM */ |
751 | if (state->has_nicam) | ||
752 | msp_write_dsp(client, 0x10, 0x5a00); /* nicam */ | ||
753 | |||
753 | if (state->has_i2s_conf) | 754 | if (state->has_i2s_conf) |
754 | msp_write_dem(client, 0x40, state->i2s_mode); | 755 | msp_write_dem(client, 0x40, state->i2s_mode); |
755 | 756 | ||
757 | /* unmute, restore misc registers */ | ||
758 | msp_set_audio(client); | ||
759 | |||
760 | msp_write_dsp(client, 0x13, state->acb); | ||
756 | msp3400c_set_audmode(client); | 761 | msp3400c_set_audmode(client); |
757 | 762 | ||
758 | /* monitor tv audio mode, the first time don't wait | 763 | /* monitor tv audio mode, the first time don't wait |
@@ -771,16 +776,15 @@ int msp3410d_thread(void *data) | |||
771 | 776 | ||
772 | /* ----------------------------------------------------------------------- */ | 777 | /* ----------------------------------------------------------------------- */ |
773 | 778 | ||
774 | /* msp34xxG + (autoselect no-thread) */ | 779 | /* msp34xxG + (autoselect no-thread) |
775 | /* this one uses both automatic standard detection and automatic sound */ | 780 | * this one uses both automatic standard detection and automatic sound |
776 | /* select which are available in the newer G versions */ | 781 | * select which are available in the newer G versions |
777 | /* struct msp: only norm, acb and source are really used in this mode */ | 782 | * struct msp: only norm, acb and source are really used in this mode |
783 | */ | ||
778 | 784 | ||
779 | /* set the same 'source' for the loudspeaker, scart and quasi-peak detector | 785 | /* set the same 'source' for the loudspeaker, scart and quasi-peak detector |
780 | * the value for source is the same as bit 15:8 of DSP registers 0x08, | 786 | * the value for source is the same as bit 15:8 of DSP registers 0x08, |
781 | * 0x0a and 0x0c: 0=mono, 1=stereo or A|B, 2=SCART, 3=stereo or A, 4=stereo or B | 787 | * 0x0a and 0x0c: 0=mono, 1=stereo or A|B, 2=SCART, 3=stereo or A, 4=stereo or B |
782 | * | ||
783 | * this function replaces msp3400c_set_audmode | ||
784 | */ | 788 | */ |
785 | static void msp34xxg_set_source(struct i2c_client *client, int source) | 789 | static void msp34xxg_set_source(struct i2c_client *client, int source) |
786 | { | 790 | { |
@@ -838,58 +842,56 @@ static int msp34xxg_modus(struct i2c_client *client) | |||
838 | return 0x0001; | 842 | return 0x0001; |
839 | } | 843 | } |
840 | 844 | ||
841 | /* (re-)initialize the msp34xxg, according to the current norm in state->norm | 845 | /* (re-)initialize the msp34xxg */ |
842 | * return 0 if it worked, -1 if it failed | 846 | static void msp34xxg_reset(struct i2c_client *client) |
843 | */ | ||
844 | static int msp34xxg_reset(struct i2c_client *client) | ||
845 | { | 847 | { |
846 | struct msp_state *state = i2c_get_clientdata(client); | 848 | struct msp_state *state = i2c_get_clientdata(client); |
847 | int modus, std; | 849 | int modus; |
848 | 850 | ||
849 | if (msp_reset(client)) | 851 | /* initialize std to 1 (autodetect) to signal that no standard is |
850 | return -1; | 852 | selected yet. */ |
853 | state->std = 1; | ||
854 | |||
855 | msp_reset(client); | ||
851 | 856 | ||
852 | /* make sure that input/output is muted (paranoid mode) */ | 857 | /* make sure that input/output is muted (paranoid mode) */ |
853 | /* ACB, mute DSP input, mute SCART 1 */ | 858 | /* ACB, mute DSP input, mute SCART 1 */ |
854 | if (msp_write_dsp(client, 0x13, 0x0f20)) | 859 | msp_write_dsp(client, 0x13, 0x0f20); |
855 | return -1; | ||
856 | 860 | ||
857 | if (state->has_i2s_conf) | 861 | if (state->has_i2s_conf) |
858 | msp_write_dem(client, 0x40, state->i2s_mode); | 862 | msp_write_dem(client, 0x40, state->i2s_mode); |
859 | 863 | ||
860 | /* step-by-step initialisation, as described in the manual */ | 864 | /* step-by-step initialisation, as described in the manual */ |
861 | modus = msp34xxg_modus(client); | 865 | modus = msp34xxg_modus(client); |
862 | if (state->radio) | 866 | msp_write_dem(client, 0x30, modus); |
863 | std = 0x40; | ||
864 | else | ||
865 | std = (state->v4l2_std & V4L2_STD_NTSC) ? 0x20 : 1; | ||
866 | modus &= ~0x03; /* STATUS_CHANGE = 0 */ | ||
867 | modus |= 0x01; /* AUTOMATIC_SOUND_DETECTION = 1 */ | ||
868 | if (msp_write_dem(client, 0x30, modus)) | ||
869 | return -1; | ||
870 | if (msp_write_dem(client, 0x20, std)) | ||
871 | return -1; | ||
872 | 867 | ||
873 | /* write the dsps that may have an influence on | 868 | /* write the dsps that may have an influence on |
874 | standard/audio autodetection right now */ | 869 | standard/audio autodetection right now */ |
875 | msp34xxg_set_source(client, state->source); | 870 | msp34xxg_set_source(client, state->source); |
876 | 871 | ||
877 | /* AM/FM Prescale [15:8] 75khz deviation */ | 872 | msp_write_dsp(client, 0x0d, 0x1900); /* scart */ |
878 | if (msp_write_dsp(client, 0x0e, 0x3000)) | 873 | msp_write_dsp(client, 0x0e, 0x3000); /* FM */ |
879 | return -1; | 874 | if (state->has_nicam) |
880 | 875 | msp_write_dsp(client, 0x10, 0x5a00); /* nicam */ | |
881 | /* NICAM Prescale 9db gain (as recommended) */ | ||
882 | if (msp_write_dsp(client, 0x10, 0x5a00)) | ||
883 | return -1; | ||
884 | 876 | ||
885 | return 0; | 877 | /* set identification threshold. Personally, I |
878 | * I set it to a higher value than the default | ||
879 | * of 0x190 to ignore noisy stereo signals. | ||
880 | * this needs tuning. (recommended range 0x00a0-0x03c0) | ||
881 | * 0x7f0 = forced mono mode | ||
882 | * | ||
883 | * a2 threshold for stereo/bilingual. | ||
884 | * Note: this register is part of the Manual/Compatibility mode. | ||
885 | * It is supported by all 'G'-family chips. | ||
886 | */ | ||
887 | msp_write_dem(client, 0x22, msp_stereo_thresh); | ||
886 | } | 888 | } |
887 | 889 | ||
888 | int msp34xxg_thread(void *data) | 890 | int msp34xxg_thread(void *data) |
889 | { | 891 | { |
890 | struct i2c_client *client = data; | 892 | struct i2c_client *client = data; |
891 | struct msp_state *state = i2c_get_clientdata(client); | 893 | struct msp_state *state = i2c_get_clientdata(client); |
892 | int val, std, i; | 894 | int val, i; |
893 | 895 | ||
894 | v4l_dbg(1, msp_debug, client, "msp34xxg daemon started\n"); | 896 | v4l_dbg(1, msp_debug, client, "msp34xxg daemon started\n"); |
895 | 897 | ||
@@ -907,12 +909,14 @@ int msp34xxg_thread(void *data) | |||
907 | 909 | ||
908 | /* setup the chip*/ | 910 | /* setup the chip*/ |
909 | msp34xxg_reset(client); | 911 | msp34xxg_reset(client); |
910 | std = msp_standard; | 912 | state->std = state->radio ? 0x40 : msp_standard; |
911 | if (std != 0x01) | 913 | if (state->std != 1) |
912 | goto unmute; | 914 | goto unmute; |
915 | /* start autodetect */ | ||
916 | msp_write_dem(client, 0x20, state->std); | ||
913 | 917 | ||
914 | /* watch autodetect */ | 918 | /* watch autodetect */ |
915 | v4l_dbg(1, msp_debug, client, "triggered autodetect, waiting for result\n"); | 919 | v4l_dbg(1, msp_debug, client, "started autodetect, waiting for result\n"); |
916 | for (i = 0; i < 10; i++) { | 920 | for (i = 0; i < 10; i++) { |
917 | if (msp_sleep(state, 100)) | 921 | if (msp_sleep(state, 100)) |
918 | goto restart; | 922 | goto restart; |
@@ -920,20 +924,19 @@ int msp34xxg_thread(void *data) | |||
920 | /* check results */ | 924 | /* check results */ |
921 | val = msp_read_dem(client, 0x7e); | 925 | val = msp_read_dem(client, 0x7e); |
922 | if (val < 0x07ff) { | 926 | if (val < 0x07ff) { |
923 | std = val; | 927 | state->std = val; |
924 | break; | 928 | break; |
925 | } | 929 | } |
926 | v4l_dbg(2, msp_debug, client, "detection still in progress\n"); | 930 | v4l_dbg(2, msp_debug, client, "detection still in progress\n"); |
927 | } | 931 | } |
928 | if (std == 1) { | 932 | if (state->std == 1) { |
929 | v4l_dbg(1, msp_debug, client, "detection still in progress after 10 tries. giving up.\n"); | 933 | v4l_dbg(1, msp_debug, client, "detection still in progress after 10 tries. giving up.\n"); |
930 | continue; | 934 | continue; |
931 | } | 935 | } |
932 | 936 | ||
933 | unmute: | 937 | unmute: |
934 | state->std = std; | 938 | v4l_dbg(1, msp_debug, client, "detected standard: %s (0x%04x)\n", |
935 | v4l_dbg(1, msp_debug, client, "current standard: %s (0x%04x)\n", | 939 | msp_standard_std_name(state->std), state->std); |
936 | msp_standard_std_name(std), std); | ||
937 | 940 | ||
938 | /* unmute: dispatch sound to scart output, set scart volume */ | 941 | /* unmute: dispatch sound to scart output, set scart volume */ |
939 | msp_set_audio(client); | 942 | msp_set_audio(client); |
@@ -942,20 +945,33 @@ int msp34xxg_thread(void *data) | |||
942 | if (msp_write_dsp(client, 0x13, state->acb)) | 945 | if (msp_write_dsp(client, 0x13, state->acb)) |
943 | return -1; | 946 | return -1; |
944 | 947 | ||
945 | if (state->has_i2s_conf) | 948 | /* the periodic stereo/SAP check is only relevant for |
946 | msp_write_dem(client, 0x40, state->i2s_mode); | 949 | the 0x20 standard (BTSC) */ |
950 | if (state->std != 0x20) | ||
951 | continue; | ||
952 | |||
953 | state->watch_stereo = 1; | ||
954 | |||
955 | /* monitor tv audio mode, the first time don't wait | ||
956 | in order to get a quick stereo/SAP update */ | ||
957 | watch_stereo(client); | ||
958 | while (state->watch_stereo) { | ||
959 | watch_stereo(client); | ||
960 | if (msp_sleep(state, 5000)) | ||
961 | goto restart; | ||
962 | } | ||
947 | } | 963 | } |
948 | v4l_dbg(1, msp_debug, client, "thread: exit\n"); | 964 | v4l_dbg(1, msp_debug, client, "thread: exit\n"); |
949 | return 0; | 965 | return 0; |
950 | } | 966 | } |
951 | 967 | ||
952 | static void msp34xxg_detect_stereo(struct i2c_client *client) | 968 | static int msp34xxg_detect_stereo(struct i2c_client *client) |
953 | { | 969 | { |
954 | struct msp_state *state = i2c_get_clientdata(client); | 970 | struct msp_state *state = i2c_get_clientdata(client); |
955 | |||
956 | int status = msp_read_dem(client, 0x0200); | 971 | int status = msp_read_dem(client, 0x0200); |
957 | int is_bilingual = status & 0x100; | 972 | int is_bilingual = status & 0x100; |
958 | int is_stereo = status & 0x40; | 973 | int is_stereo = status & 0x40; |
974 | int oldrx = state->rxsubchans; | ||
959 | 975 | ||
960 | state->rxsubchans = 0; | 976 | state->rxsubchans = 0; |
961 | if (is_stereo) | 977 | if (is_stereo) |
@@ -963,16 +979,14 @@ static void msp34xxg_detect_stereo(struct i2c_client *client) | |||
963 | else | 979 | else |
964 | state->rxsubchans = V4L2_TUNER_SUB_MONO; | 980 | state->rxsubchans = V4L2_TUNER_SUB_MONO; |
965 | if (is_bilingual) { | 981 | if (is_bilingual) { |
966 | state->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; | 982 | if (state->std == 0x20) |
967 | /* I'm supposed to check whether it's SAP or not | 983 | state->rxsubchans |= V4L2_TUNER_SUB_SAP; |
968 | * and set only LANG2/SAP in this case. Yet, the MSP | 984 | else |
969 | * does a lot of work to hide this and handle everything | 985 | state->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; |
970 | * the same way. I don't want to work around it so unless | ||
971 | * this is a problem, I'll handle SAP just like lang1/lang2. | ||
972 | */ | ||
973 | } | 986 | } |
974 | v4l_dbg(1, msp_debug, client, "status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n", | 987 | v4l_dbg(1, msp_debug, client, "status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n", |
975 | status, is_stereo, is_bilingual, state->rxsubchans); | 988 | status, is_stereo, is_bilingual, state->rxsubchans); |
989 | return (oldrx != state->rxsubchans); | ||
976 | } | 990 | } |
977 | 991 | ||
978 | static void msp34xxg_set_audmode(struct i2c_client *client) | 992 | static void msp34xxg_set_audmode(struct i2c_client *client) |
@@ -980,6 +994,16 @@ static void msp34xxg_set_audmode(struct i2c_client *client) | |||
980 | struct msp_state *state = i2c_get_clientdata(client); | 994 | struct msp_state *state = i2c_get_clientdata(client); |
981 | int source; | 995 | int source; |
982 | 996 | ||
997 | if (state->std == 0x20) { | ||
998 | if ((state->rxsubchans & V4L2_TUNER_SUB_SAP) && | ||
999 | (state->audmode == V4L2_TUNER_MODE_STEREO || | ||
1000 | state->audmode == V4L2_TUNER_MODE_LANG2)) { | ||
1001 | msp_write_dem(client, 0x20, 0x21); | ||
1002 | } else { | ||
1003 | msp_write_dem(client, 0x20, 0x20); | ||
1004 | } | ||
1005 | } | ||
1006 | |||
983 | switch (state->audmode) { | 1007 | switch (state->audmode) { |
984 | case V4L2_TUNER_MODE_MONO: | 1008 | case V4L2_TUNER_MODE_MONO: |
985 | source = 0; /* mono only */ | 1009 | source = 0; /* mono only */ |
@@ -1008,7 +1032,6 @@ void msp_set_audmode(struct i2c_client *client) | |||
1008 | switch (state->opmode) { | 1032 | switch (state->opmode) { |
1009 | case OPMODE_MANUAL: | 1033 | case OPMODE_MANUAL: |
1010 | case OPMODE_AUTODETECT: | 1034 | case OPMODE_AUTODETECT: |
1011 | state->watch_stereo = 0; | ||
1012 | msp3400c_set_audmode(client); | 1035 | msp3400c_set_audmode(client); |
1013 | break; | 1036 | break; |
1014 | case OPMODE_AUTOSELECT: | 1037 | case OPMODE_AUTOSELECT: |
@@ -1017,18 +1040,17 @@ void msp_set_audmode(struct i2c_client *client) | |||
1017 | } | 1040 | } |
1018 | } | 1041 | } |
1019 | 1042 | ||
1020 | void msp_detect_stereo(struct i2c_client *client) | 1043 | int msp_detect_stereo(struct i2c_client *client) |
1021 | { | 1044 | { |
1022 | struct msp_state *state = i2c_get_clientdata(client); | 1045 | struct msp_state *state = i2c_get_clientdata(client); |
1023 | 1046 | ||
1024 | switch (state->opmode) { | 1047 | switch (state->opmode) { |
1025 | case OPMODE_MANUAL: | 1048 | case OPMODE_MANUAL: |
1026 | case OPMODE_AUTODETECT: | 1049 | case OPMODE_AUTODETECT: |
1027 | msp3400c_detect_stereo(client); | 1050 | return msp3400c_detect_stereo(client); |
1028 | break; | ||
1029 | case OPMODE_AUTOSELECT: | 1051 | case OPMODE_AUTOSELECT: |
1030 | msp34xxg_detect_stereo(client); | 1052 | return msp34xxg_detect_stereo(client); |
1031 | break; | ||
1032 | } | 1053 | } |
1054 | return 0; | ||
1033 | } | 1055 | } |
1034 | 1056 | ||