diff options
Diffstat (limited to 'drivers/media/video/msp3400-kthreads.c')
-rw-r--r-- | drivers/media/video/msp3400-kthreads.c | 331 |
1 files changed, 199 insertions, 132 deletions
diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c index 852ab6a115fa..c3984ea9ca07 100644 --- a/drivers/media/video/msp3400-kthreads.c +++ b/drivers/media/video/msp3400-kthreads.c | |||
@@ -26,10 +26,10 @@ | |||
26 | #include <linux/videodev.h> | 26 | #include <linux/videodev.h> |
27 | #include <linux/videodev2.h> | 27 | #include <linux/videodev2.h> |
28 | #include <media/v4l2-common.h> | 28 | #include <media/v4l2-common.h> |
29 | #include <media/audiochip.h> | 29 | #include <media/msp3400.h> |
30 | #include <linux/kthread.h> | 30 | #include <linux/kthread.h> |
31 | #include <linux/suspend.h> | 31 | #include <linux/suspend.h> |
32 | #include "msp3400.h" | 32 | #include "msp3400-driver.h" |
33 | 33 | ||
34 | /* this one uses the automatic sound standard detection of newer msp34xx | 34 | /* this one uses the automatic sound standard detection of newer msp34xx |
35 | chip versions */ | 35 | chip versions */ |
@@ -45,11 +45,13 @@ static struct { | |||
45 | { 0x0004, MSP_CARRIER(6.5), MSP_CARRIER(6.2578125), "6.5/6.25 D/K1 Dual FM-Stereo" }, | 45 | { 0x0004, MSP_CARRIER(6.5), MSP_CARRIER(6.2578125), "6.5/6.25 D/K1 Dual FM-Stereo" }, |
46 | { 0x0005, MSP_CARRIER(6.5), MSP_CARRIER(6.7421875), "6.5/6.74 D/K2 Dual FM-Stereo" }, | 46 | { 0x0005, MSP_CARRIER(6.5), MSP_CARRIER(6.7421875), "6.5/6.74 D/K2 Dual FM-Stereo" }, |
47 | { 0x0006, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5 D/K FM-Mono (HDEV3)" }, | 47 | { 0x0006, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5 D/K FM-Mono (HDEV3)" }, |
48 | { 0x0007, MSP_CARRIER(6.5), MSP_CARRIER(5.7421875), "6.5/5.74 D/K3 Dual FM-Stereo" }, | ||
48 | { 0x0008, MSP_CARRIER(5.5), MSP_CARRIER(5.85), "5.5/5.85 B/G NICAM FM" }, | 49 | { 0x0008, MSP_CARRIER(5.5), MSP_CARRIER(5.85), "5.5/5.85 B/G NICAM FM" }, |
49 | { 0x0009, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 L NICAM AM" }, | 50 | { 0x0009, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 L NICAM AM" }, |
50 | { 0x000a, MSP_CARRIER(6.0), MSP_CARRIER(6.55), "6.0/6.55 I NICAM FM" }, | 51 | { 0x000a, MSP_CARRIER(6.0), MSP_CARRIER(6.55), "6.0/6.55 I NICAM FM" }, |
51 | { 0x000b, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM" }, | 52 | { 0x000b, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM" }, |
52 | { 0x000c, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM (HDEV2)" }, | 53 | { 0x000c, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM (HDEV2)" }, |
54 | { 0x000d, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM (HDEV3)" }, | ||
53 | { 0x0020, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M BTSC-Stereo" }, | 55 | { 0x0020, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M BTSC-Stereo" }, |
54 | { 0x0021, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M BTSC-Mono + SAP" }, | 56 | { 0x0021, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M BTSC-Mono + SAP" }, |
55 | { 0x0030, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M EIA-J Japan Stereo" }, | 57 | { 0x0030, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M EIA-J Japan Stereo" }, |
@@ -185,13 +187,14 @@ void msp3400c_set_mode(struct i2c_client *client, int mode) | |||
185 | { | 187 | { |
186 | struct msp_state *state = i2c_get_clientdata(client); | 188 | struct msp_state *state = i2c_get_clientdata(client); |
187 | struct msp3400c_init_data_dem *data = &msp3400c_init_data[mode]; | 189 | struct msp3400c_init_data_dem *data = &msp3400c_init_data[mode]; |
190 | int tuner = (state->routing.input >> 3) & 1; | ||
188 | int i; | 191 | int i; |
189 | 192 | ||
190 | v4l_dbg(1, msp_debug, client, "set_mode: %d\n", mode); | 193 | v4l_dbg(1, msp_debug, client, "set_mode: %d\n", mode); |
191 | state->mode = mode; | 194 | state->mode = mode; |
192 | state->rxsubchans = V4L2_TUNER_SUB_MONO; | 195 | state->rxsubchans = V4L2_TUNER_SUB_MONO; |
193 | 196 | ||
194 | msp_write_dem(client, 0x00bb, data->ad_cv); | 197 | msp_write_dem(client, 0x00bb, data->ad_cv | (tuner ? 0x100 : 0)); |
195 | 198 | ||
196 | for (i = 5; i >= 0; i--) /* fir 1 */ | 199 | for (i = 5; i >= 0; i--) /* fir 1 */ |
197 | msp_write_dem(client, 0x0001, data->fir1[i]); | 200 | msp_write_dem(client, 0x0001, data->fir1[i]); |
@@ -207,21 +210,22 @@ void msp3400c_set_mode(struct i2c_client *client, int mode) | |||
207 | msp3400c_set_carrier(client, data->cdo1, data->cdo2); | 210 | msp3400c_set_carrier(client, data->cdo1, data->cdo2); |
208 | 211 | ||
209 | msp_set_source(client, data->dsp_src); | 212 | msp_set_source(client, data->dsp_src); |
210 | msp_write_dsp(client, 0x000e, data->dsp_matrix); | 213 | /* set prescales */ |
211 | 214 | ||
212 | if (state->has_nicam) { | 215 | /* volume prescale for SCART (AM mono input) */ |
213 | /* nicam prescale */ | 216 | msp_write_dsp(client, 0x000d, 0x1900); |
214 | msp_write_dsp(client, 0x0010, 0x5a00); /* was: 0x3000 */ | 217 | msp_write_dsp(client, 0x000e, data->dsp_matrix); |
215 | } | 218 | if (state->has_nicam) /* nicam prescale */ |
219 | msp_write_dsp(client, 0x0010, 0x5a00); | ||
216 | } | 220 | } |
217 | 221 | ||
218 | /* Set audio mode. Note that the pre-'G' models do not support BTSC+SAP, | 222 | /* Set audio mode. Note that the pre-'G' models do not support BTSC+SAP, |
219 | nor do they support stereo BTSC. */ | 223 | nor do they support stereo BTSC. */ |
220 | static void msp3400c_set_audmode(struct i2c_client *client) | 224 | static void msp3400c_set_audmode(struct i2c_client *client) |
221 | { | 225 | { |
222 | static char *strmode[] = { "mono", "stereo", "lang2", "lang1" }; | 226 | static char *strmode[] = { "mono", "stereo", "lang2", "lang1", "lang1+lang2" }; |
223 | struct msp_state *state = i2c_get_clientdata(client); | 227 | struct msp_state *state = i2c_get_clientdata(client); |
224 | char *modestr = (state->audmode >= 0 && state->audmode < 4) ? | 228 | char *modestr = (state->audmode >= 0 && state->audmode < 5) ? |
225 | strmode[state->audmode] : "unknown"; | 229 | strmode[state->audmode] : "unknown"; |
226 | int src = 0; /* channel source: FM/AM, nicam or SCART */ | 230 | int src = 0; /* channel source: FM/AM, nicam or SCART */ |
227 | 231 | ||
@@ -246,6 +250,7 @@ static void msp3400c_set_audmode(struct i2c_client *client) | |||
246 | case V4L2_TUNER_MODE_MONO: | 250 | case V4L2_TUNER_MODE_MONO: |
247 | case V4L2_TUNER_MODE_LANG1: | 251 | case V4L2_TUNER_MODE_LANG1: |
248 | case V4L2_TUNER_MODE_LANG2: | 252 | case V4L2_TUNER_MODE_LANG2: |
253 | case V4L2_TUNER_MODE_LANG1_LANG2: | ||
249 | msp_write_dsp(client, 0x000e, 0x3000); | 254 | msp_write_dsp(client, 0x000e, 0x3000); |
250 | break; | 255 | break; |
251 | } | 256 | } |
@@ -257,6 +262,7 @@ static void msp3400c_set_audmode(struct i2c_client *client) | |||
257 | msp3400c_set_carrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5)); | 262 | msp3400c_set_carrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5)); |
258 | break; | 263 | break; |
259 | case V4L2_TUNER_MODE_STEREO: | 264 | case V4L2_TUNER_MODE_STEREO: |
265 | case V4L2_TUNER_MODE_LANG1_LANG2: | ||
260 | msp3400c_set_carrier(client, MSP_CARRIER(7.2), MSP_CARRIER(7.02)); | 266 | msp3400c_set_carrier(client, MSP_CARRIER(7.2), MSP_CARRIER(7.02)); |
261 | break; | 267 | break; |
262 | case V4L2_TUNER_MODE_LANG1: | 268 | case V4L2_TUNER_MODE_LANG1: |
@@ -271,7 +277,6 @@ static void msp3400c_set_audmode(struct i2c_client *client) | |||
271 | case MSP_MODE_FM_NICAM2: | 277 | case MSP_MODE_FM_NICAM2: |
272 | case MSP_MODE_AM_NICAM: | 278 | case MSP_MODE_AM_NICAM: |
273 | v4l_dbg(1, msp_debug, client, "NICAM set_audmode: %s\n",modestr); | 279 | v4l_dbg(1, msp_debug, client, "NICAM set_audmode: %s\n",modestr); |
274 | msp3400c_set_carrier(client, state->second, state->main); | ||
275 | if (state->nicam_on) | 280 | if (state->nicam_on) |
276 | src = 0x0100; /* NICAM */ | 281 | src = 0x0100; /* NICAM */ |
277 | break; | 282 | break; |
@@ -293,6 +298,7 @@ static void msp3400c_set_audmode(struct i2c_client *client) | |||
293 | /* switch audio */ | 298 | /* switch audio */ |
294 | switch (state->audmode) { | 299 | switch (state->audmode) { |
295 | case V4L2_TUNER_MODE_STEREO: | 300 | case V4L2_TUNER_MODE_STEREO: |
301 | case V4L2_TUNER_MODE_LANG1_LANG2: | ||
296 | src |= 0x0020; | 302 | src |= 0x0020; |
297 | break; | 303 | break; |
298 | case V4L2_TUNER_MODE_MONO: | 304 | case V4L2_TUNER_MODE_MONO: |
@@ -427,8 +433,8 @@ static void watch_stereo(struct i2c_client *client) | |||
427 | { | 433 | { |
428 | struct msp_state *state = i2c_get_clientdata(client); | 434 | struct msp_state *state = i2c_get_clientdata(client); |
429 | 435 | ||
430 | if (msp3400c_detect_stereo(client)) { | 436 | if (msp_detect_stereo(client)) { |
431 | msp3400c_set_audmode(client); | 437 | msp_set_audmode(client); |
432 | } | 438 | } |
433 | 439 | ||
434 | if (msp_once) | 440 | if (msp_once) |
@@ -464,7 +470,7 @@ int msp3400c_thread(void *data) | |||
464 | 470 | ||
465 | /* mute */ | 471 | /* mute */ |
466 | msp_set_mute(client); | 472 | msp_set_mute(client); |
467 | msp3400c_set_mode(client, MSP_MODE_AM_DETECT /* +1 */ ); | 473 | msp3400c_set_mode(client, MSP_MODE_AM_DETECT); |
468 | val1 = val2 = 0; | 474 | val1 = val2 = 0; |
469 | max1 = max2 = -1; | 475 | max1 = max2 = -1; |
470 | state->watch_stereo = 0; | 476 | state->watch_stereo = 0; |
@@ -572,8 +578,6 @@ int msp3400c_thread(void *data) | |||
572 | state->second = msp3400c_carrier_detect_65[max2].cdo; | 578 | state->second = msp3400c_carrier_detect_65[max2].cdo; |
573 | msp3400c_set_mode(client, MSP_MODE_AM_NICAM); | 579 | msp3400c_set_mode(client, MSP_MODE_AM_NICAM); |
574 | msp3400c_set_carrier(client, state->second, state->main); | 580 | msp3400c_set_carrier(client, state->second, state->main); |
575 | /* volume prescale for SCART (AM mono input) */ | ||
576 | msp_write_dsp(client, 0x000d, 0x1900); | ||
577 | state->watch_stereo = 1; | 581 | state->watch_stereo = 1; |
578 | } else if (max2 == 0 && state->has_nicam) { | 582 | } else if (max2 == 0 && state->has_nicam) { |
579 | /* D/K NICAM */ | 583 | /* D/K NICAM */ |
@@ -651,7 +655,8 @@ int msp3410d_thread(void *data) | |||
651 | if (msp_sleep(state,200)) | 655 | if (msp_sleep(state,200)) |
652 | goto restart; | 656 | goto restart; |
653 | 657 | ||
654 | /* start autodetect */ | 658 | /* start autodetect. Note: autodetect is not supported for |
659 | NTSC-M and radio, hence we force the standard in those cases. */ | ||
655 | if (state->radio) | 660 | if (state->radio) |
656 | std = 0x40; | 661 | std = 0x40; |
657 | else | 662 | else |
@@ -695,23 +700,19 @@ int msp3410d_thread(void *data) | |||
695 | v4l_dbg(1, msp_debug, client, "autodetection failed," | 700 | v4l_dbg(1, msp_debug, client, "autodetection failed," |
696 | " switching to backup standard: %s (0x%04x)\n", | 701 | " switching to backup standard: %s (0x%04x)\n", |
697 | msp_stdlist[8].name ? msp_stdlist[8].name : "unknown",val); | 702 | msp_stdlist[8].name ? msp_stdlist[8].name : "unknown",val); |
698 | val = 0x0009; | 703 | state->std = val = 0x0009; |
699 | msp_write_dem(client, 0x20, val); | 704 | msp_write_dem(client, 0x20, val); |
700 | } | 705 | } |
701 | 706 | ||
702 | /* set various prescales */ | ||
703 | msp_write_dsp(client, 0x0d, 0x1900); /* scart */ | ||
704 | msp_write_dsp(client, 0x0e, 0x2403); /* FM */ | ||
705 | msp_write_dsp(client, 0x10, 0x5a00); /* nicam */ | ||
706 | |||
707 | /* set stereo */ | 707 | /* set stereo */ |
708 | switch (val) { | 708 | switch (val) { |
709 | case 0x0008: /* B/G NICAM */ | 709 | case 0x0008: /* B/G NICAM */ |
710 | case 0x000a: /* I NICAM */ | 710 | case 0x000a: /* I NICAM */ |
711 | if (val == 0x0008) | 711 | case 0x000b: /* D/K NICAM */ |
712 | state->mode = MSP_MODE_FM_NICAM1; | 712 | if (val == 0x000a) |
713 | else | ||
714 | state->mode = MSP_MODE_FM_NICAM2; | 713 | state->mode = MSP_MODE_FM_NICAM2; |
714 | else | ||
715 | state->mode = MSP_MODE_FM_NICAM1; | ||
715 | /* just turn on stereo */ | 716 | /* just turn on stereo */ |
716 | state->rxsubchans = V4L2_TUNER_SUB_STEREO; | 717 | state->rxsubchans = V4L2_TUNER_SUB_STEREO; |
717 | state->nicam_on = 1; | 718 | state->nicam_on = 1; |
@@ -739,6 +740,7 @@ int msp3410d_thread(void *data) | |||
739 | /* scart routing (this doesn't belong here I think) */ | 740 | /* scart routing (this doesn't belong here I think) */ |
740 | msp_set_scart(client,SCART_IN2,0); | 741 | msp_set_scart(client,SCART_IN2,0); |
741 | break; | 742 | break; |
743 | case 0x0002: | ||
742 | case 0x0003: | 744 | case 0x0003: |
743 | case 0x0004: | 745 | case 0x0004: |
744 | case 0x0005: | 746 | case 0x0005: |
@@ -748,12 +750,19 @@ int msp3410d_thread(void *data) | |||
748 | break; | 750 | break; |
749 | } | 751 | } |
750 | 752 | ||
751 | /* unmute, restore misc registers */ | 753 | /* set various prescales */ |
752 | msp_set_audio(client); | 754 | msp_write_dsp(client, 0x0d, 0x1900); /* scart */ |
753 | msp_write_dsp(client, 0x13, state->acb); | 755 | msp_write_dsp(client, 0x0e, 0x3000); /* FM */ |
756 | if (state->has_nicam) | ||
757 | msp_write_dsp(client, 0x10, 0x5a00); /* nicam */ | ||
758 | |||
754 | if (state->has_i2s_conf) | 759 | if (state->has_i2s_conf) |
755 | msp_write_dem(client, 0x40, state->i2s_mode); | 760 | msp_write_dem(client, 0x40, state->i2s_mode); |
756 | 761 | ||
762 | /* unmute, restore misc registers */ | ||
763 | msp_set_audio(client); | ||
764 | |||
765 | msp_write_dsp(client, 0x13, state->acb); | ||
757 | msp3400c_set_audmode(client); | 766 | msp3400c_set_audmode(client); |
758 | 767 | ||
759 | /* monitor tv audio mode, the first time don't wait | 768 | /* monitor tv audio mode, the first time don't wait |
@@ -772,97 +781,154 @@ int msp3410d_thread(void *data) | |||
772 | 781 | ||
773 | /* ----------------------------------------------------------------------- */ | 782 | /* ----------------------------------------------------------------------- */ |
774 | 783 | ||
775 | /* msp34xxG + (autoselect no-thread) */ | 784 | /* msp34xxG + (autoselect no-thread) |
776 | /* this one uses both automatic standard detection and automatic sound */ | 785 | * this one uses both automatic standard detection and automatic sound |
777 | /* select which are available in the newer G versions */ | 786 | * select which are available in the newer G versions |
778 | /* struct msp: only norm, acb and source are really used in this mode */ | 787 | * struct msp: only norm, acb and source are really used in this mode |
779 | |||
780 | /* set the same 'source' for the loudspeaker, scart and quasi-peak detector | ||
781 | * the value for source is the same as bit 15:8 of DSP registers 0x08, | ||
782 | * 0x0a and 0x0c: 0=mono, 1=stereo or A|B, 2=SCART, 3=stereo or A, 4=stereo or B | ||
783 | * | ||
784 | * this function replaces msp3400c_set_audmode | ||
785 | */ | 788 | */ |
786 | static void msp34xxg_set_source(struct i2c_client *client, int source) | 789 | |
790 | static int msp34xxg_modus(struct i2c_client *client) | ||
787 | { | 791 | { |
788 | struct msp_state *state = i2c_get_clientdata(client); | 792 | struct msp_state *state = i2c_get_clientdata(client); |
789 | 793 | ||
790 | /* fix matrix mode to stereo and let the msp choose what | 794 | if (state->radio) { |
791 | * to output according to 'source', as recommended | 795 | v4l_dbg(1, msp_debug, client, "selected radio modus\n"); |
792 | * for MONO (source==0) downmixing set bit[7:0] to 0x30 | 796 | return 0x0001; |
793 | */ | 797 | } |
794 | int value = (source & 0x07) << 8 | (source == 0 ? 0x30 : 0x20); | ||
795 | 798 | ||
796 | v4l_dbg(1, msp_debug, client, "set source to %d (0x%x)\n", source, value); | 799 | if (state->v4l2_std & V4L2_STD_PAL) { |
797 | msp_set_source(client, value); | 800 | v4l_dbg(1, msp_debug, client, "selected PAL modus\n"); |
798 | /* | 801 | return 0x7001; |
799 | * set identification threshold. Personally, I | 802 | } |
800 | * I set it to a higher value that the default | 803 | if (state->v4l2_std == V4L2_STD_NTSC_M_JP) { |
801 | * of 0x190 to ignore noisy stereo signals. | 804 | v4l_dbg(1, msp_debug, client, "selected M (EIA-J) modus\n"); |
802 | * this needs tuning. (recommended range 0x00a0-0x03c0) | 805 | return 0x4001; |
803 | * 0x7f0 = forced mono mode | 806 | } |
804 | */ | 807 | if (state->v4l2_std == V4L2_STD_NTSC_M_KR) { |
805 | /* a2 threshold for stereo/bilingual */ | 808 | v4l_dbg(1, msp_debug, client, "selected M (A2) modus\n"); |
806 | msp_write_dem(client, 0x22, msp_stereo_thresh); | 809 | return 0x0001; |
807 | state->source = source; | 810 | } |
811 | if (state->v4l2_std & V4L2_STD_MN) { | ||
812 | v4l_dbg(1, msp_debug, client, "selected M (BTSC) modus\n"); | ||
813 | return 0x2001; | ||
814 | } | ||
815 | if (state->v4l2_std & V4L2_STD_SECAM) { | ||
816 | v4l_dbg(1, msp_debug, client, "selected SECAM modus\n"); | ||
817 | return 0x6001; | ||
818 | } | ||
819 | return 0x0001; | ||
808 | } | 820 | } |
809 | 821 | ||
810 | /* (re-)initialize the msp34xxg, according to the current norm in state->norm | 822 | static void msp34xxg_set_source(struct i2c_client *client, u16 reg, int in) |
811 | * return 0 if it worked, -1 if it failed | 823 | { |
812 | */ | 824 | struct msp_state *state = i2c_get_clientdata(client); |
813 | static int msp34xxg_reset(struct i2c_client *client) | 825 | int source, matrix; |
826 | |||
827 | switch (state->audmode) { | ||
828 | case V4L2_TUNER_MODE_MONO: | ||
829 | source = 0; /* mono only */ | ||
830 | matrix = 0x30; | ||
831 | break; | ||
832 | case V4L2_TUNER_MODE_LANG1: | ||
833 | source = 3; /* stereo or A */ | ||
834 | matrix = 0x00; | ||
835 | break; | ||
836 | case V4L2_TUNER_MODE_LANG2: | ||
837 | source = 4; /* stereo or B */ | ||
838 | matrix = 0x10; | ||
839 | break; | ||
840 | case V4L2_TUNER_MODE_STEREO: | ||
841 | case V4L2_TUNER_MODE_LANG1_LANG2: | ||
842 | default: | ||
843 | source = 1; /* stereo or A|B */ | ||
844 | matrix = 0x20; | ||
845 | break; | ||
846 | } | ||
847 | |||
848 | if (in == MSP_DSP_OUT_TUNER) | ||
849 | source = (source << 8) | 0x20; | ||
850 | /* the msp34x2g puts the MAIN_AVC, MAIN and AUX sources in 12, 13, 14 | ||
851 | instead of 11, 12, 13. So we add one for that msp version. */ | ||
852 | else if (in >= MSP_DSP_OUT_MAIN_AVC && state->has_dolby_pro_logic) | ||
853 | source = ((in + 1) << 8) | matrix; | ||
854 | else | ||
855 | source = (in << 8) | matrix; | ||
856 | |||
857 | v4l_dbg(1, msp_debug, client, "set source to %d (0x%x) for output %02x\n", | ||
858 | in, source, reg); | ||
859 | msp_write_dsp(client, reg, source); | ||
860 | } | ||
861 | |||
862 | static void msp34xxg_set_sources(struct i2c_client *client) | ||
863 | { | ||
864 | struct msp_state *state = i2c_get_clientdata(client); | ||
865 | u32 in = state->routing.input; | ||
866 | |||
867 | msp34xxg_set_source(client, 0x0008, (in >> 4) & 0xf); | ||
868 | /* quasi-peak detector is set to same input as the loudspeaker (MAIN) */ | ||
869 | msp34xxg_set_source(client, 0x000c, (in >> 4) & 0xf); | ||
870 | msp34xxg_set_source(client, 0x0009, (in >> 8) & 0xf); | ||
871 | msp34xxg_set_source(client, 0x000a, (in >> 12) & 0xf); | ||
872 | if (state->has_scart23_in_scart2_out) | ||
873 | msp34xxg_set_source(client, 0x0041, (in >> 16) & 0xf); | ||
874 | msp34xxg_set_source(client, 0x000b, (in >> 20) & 0xf); | ||
875 | } | ||
876 | |||
877 | /* (re-)initialize the msp34xxg */ | ||
878 | static void msp34xxg_reset(struct i2c_client *client) | ||
814 | { | 879 | { |
815 | struct msp_state *state = i2c_get_clientdata(client); | 880 | struct msp_state *state = i2c_get_clientdata(client); |
816 | int modus, std; | 881 | int tuner = (state->routing.input >> 3) & 1; |
882 | int modus; | ||
883 | |||
884 | /* initialize std to 1 (autodetect) to signal that no standard is | ||
885 | selected yet. */ | ||
886 | state->std = 1; | ||
817 | 887 | ||
818 | if (msp_reset(client)) | 888 | msp_reset(client); |
819 | return -1; | ||
820 | 889 | ||
821 | /* make sure that input/output is muted (paranoid mode) */ | 890 | /* make sure that input/output is muted (paranoid mode) */ |
822 | /* ACB, mute DSP input, mute SCART 1 */ | 891 | /* ACB, mute DSP input, mute SCART 1 */ |
823 | if (msp_write_dsp(client, 0x13, 0x0f20)) | 892 | msp_write_dsp(client, 0x13, 0x0f20); |
824 | return -1; | ||
825 | 893 | ||
826 | if (state->has_i2s_conf) | 894 | if (state->has_i2s_conf) |
827 | msp_write_dem(client, 0x40, state->i2s_mode); | 895 | msp_write_dem(client, 0x40, state->i2s_mode); |
828 | 896 | ||
829 | /* step-by-step initialisation, as described in the manual */ | 897 | /* step-by-step initialisation, as described in the manual */ |
830 | modus = msp_modus(client); | 898 | modus = msp34xxg_modus(client); |
831 | if (state->radio) | 899 | modus |= tuner ? 0x100 : 0; |
832 | std = 0x40; | 900 | msp_write_dem(client, 0x30, modus); |
833 | else | ||
834 | std = (state->v4l2_std & V4L2_STD_NTSC) ? 0x20 : 1; | ||
835 | modus &= ~0x03; /* STATUS_CHANGE = 0 */ | ||
836 | modus |= 0x01; /* AUTOMATIC_SOUND_DETECTION = 1 */ | ||
837 | if (msp_write_dem(client, 0x30, modus)) | ||
838 | return -1; | ||
839 | if (msp_write_dem(client, 0x20, std)) | ||
840 | return -1; | ||
841 | 901 | ||
842 | /* write the dsps that may have an influence on | 902 | /* write the dsps that may have an influence on |
843 | standard/audio autodetection right now */ | 903 | standard/audio autodetection right now */ |
844 | msp34xxg_set_source(client, state->source); | 904 | msp34xxg_set_sources(client); |
845 | |||
846 | /* AM/FM Prescale [15:8] 75khz deviation */ | ||
847 | if (msp_write_dsp(client, 0x0e, 0x3000)) | ||
848 | return -1; | ||
849 | 905 | ||
850 | /* NICAM Prescale 9db gain (as recommended) */ | 906 | msp_write_dsp(client, 0x0d, 0x1900); /* scart */ |
851 | if (msp_write_dsp(client, 0x10, 0x5a00)) | 907 | msp_write_dsp(client, 0x0e, 0x3000); /* FM */ |
852 | return -1; | 908 | if (state->has_nicam) |
909 | msp_write_dsp(client, 0x10, 0x5a00); /* nicam */ | ||
853 | 910 | ||
854 | return 0; | 911 | /* set identification threshold. Personally, I |
912 | * I set it to a higher value than the default | ||
913 | * of 0x190 to ignore noisy stereo signals. | ||
914 | * this needs tuning. (recommended range 0x00a0-0x03c0) | ||
915 | * 0x7f0 = forced mono mode | ||
916 | * | ||
917 | * a2 threshold for stereo/bilingual. | ||
918 | * Note: this register is part of the Manual/Compatibility mode. | ||
919 | * It is supported by all 'G'-family chips. | ||
920 | */ | ||
921 | msp_write_dem(client, 0x22, msp_stereo_thresh); | ||
855 | } | 922 | } |
856 | 923 | ||
857 | int msp34xxg_thread(void *data) | 924 | int msp34xxg_thread(void *data) |
858 | { | 925 | { |
859 | struct i2c_client *client = data; | 926 | struct i2c_client *client = data; |
860 | struct msp_state *state = i2c_get_clientdata(client); | 927 | struct msp_state *state = i2c_get_clientdata(client); |
861 | int val, std, i; | 928 | int val, i; |
862 | 929 | ||
863 | v4l_dbg(1, msp_debug, client, "msp34xxg daemon started\n"); | 930 | v4l_dbg(1, msp_debug, client, "msp34xxg daemon started\n"); |
864 | 931 | ||
865 | state->source = 1; /* default */ | ||
866 | for (;;) { | 932 | for (;;) { |
867 | v4l_dbg(2, msp_debug, client, "msp34xxg thread: sleep\n"); | 933 | v4l_dbg(2, msp_debug, client, "msp34xxg thread: sleep\n"); |
868 | msp_sleep(state, -1); | 934 | msp_sleep(state, -1); |
@@ -876,12 +942,14 @@ int msp34xxg_thread(void *data) | |||
876 | 942 | ||
877 | /* setup the chip*/ | 943 | /* setup the chip*/ |
878 | msp34xxg_reset(client); | 944 | msp34xxg_reset(client); |
879 | std = msp_standard; | 945 | state->std = state->radio ? 0x40 : msp_standard; |
880 | if (std != 0x01) | 946 | if (state->std != 1) |
881 | goto unmute; | 947 | goto unmute; |
948 | /* start autodetect */ | ||
949 | msp_write_dem(client, 0x20, state->std); | ||
882 | 950 | ||
883 | /* watch autodetect */ | 951 | /* watch autodetect */ |
884 | v4l_dbg(1, msp_debug, client, "triggered autodetect, waiting for result\n"); | 952 | v4l_dbg(1, msp_debug, client, "started autodetect, waiting for result\n"); |
885 | for (i = 0; i < 10; i++) { | 953 | for (i = 0; i < 10; i++) { |
886 | if (msp_sleep(state, 100)) | 954 | if (msp_sleep(state, 100)) |
887 | goto restart; | 955 | goto restart; |
@@ -889,20 +957,19 @@ int msp34xxg_thread(void *data) | |||
889 | /* check results */ | 957 | /* check results */ |
890 | val = msp_read_dem(client, 0x7e); | 958 | val = msp_read_dem(client, 0x7e); |
891 | if (val < 0x07ff) { | 959 | if (val < 0x07ff) { |
892 | std = val; | 960 | state->std = val; |
893 | break; | 961 | break; |
894 | } | 962 | } |
895 | v4l_dbg(2, msp_debug, client, "detection still in progress\n"); | 963 | v4l_dbg(2, msp_debug, client, "detection still in progress\n"); |
896 | } | 964 | } |
897 | if (std == 1) { | 965 | if (state->std == 1) { |
898 | v4l_dbg(1, msp_debug, client, "detection still in progress after 10 tries. giving up.\n"); | 966 | v4l_dbg(1, msp_debug, client, "detection still in progress after 10 tries. giving up.\n"); |
899 | continue; | 967 | continue; |
900 | } | 968 | } |
901 | 969 | ||
902 | unmute: | 970 | unmute: |
903 | state->std = std; | 971 | v4l_dbg(1, msp_debug, client, "detected standard: %s (0x%04x)\n", |
904 | v4l_dbg(1, msp_debug, client, "current standard: %s (0x%04x)\n", | 972 | msp_standard_std_name(state->std), state->std); |
905 | msp_standard_std_name(std), std); | ||
906 | 973 | ||
907 | /* unmute: dispatch sound to scart output, set scart volume */ | 974 | /* unmute: dispatch sound to scart output, set scart volume */ |
908 | msp_set_audio(client); | 975 | msp_set_audio(client); |
@@ -911,20 +978,33 @@ int msp34xxg_thread(void *data) | |||
911 | if (msp_write_dsp(client, 0x13, state->acb)) | 978 | if (msp_write_dsp(client, 0x13, state->acb)) |
912 | return -1; | 979 | return -1; |
913 | 980 | ||
914 | if (state->has_i2s_conf) | 981 | /* the periodic stereo/SAP check is only relevant for |
915 | msp_write_dem(client, 0x40, state->i2s_mode); | 982 | the 0x20 standard (BTSC) */ |
983 | if (state->std != 0x20) | ||
984 | continue; | ||
985 | |||
986 | state->watch_stereo = 1; | ||
987 | |||
988 | /* monitor tv audio mode, the first time don't wait | ||
989 | in order to get a quick stereo/SAP update */ | ||
990 | watch_stereo(client); | ||
991 | while (state->watch_stereo) { | ||
992 | watch_stereo(client); | ||
993 | if (msp_sleep(state, 5000)) | ||
994 | goto restart; | ||
995 | } | ||
916 | } | 996 | } |
917 | v4l_dbg(1, msp_debug, client, "thread: exit\n"); | 997 | v4l_dbg(1, msp_debug, client, "thread: exit\n"); |
918 | return 0; | 998 | return 0; |
919 | } | 999 | } |
920 | 1000 | ||
921 | static void msp34xxg_detect_stereo(struct i2c_client *client) | 1001 | static int msp34xxg_detect_stereo(struct i2c_client *client) |
922 | { | 1002 | { |
923 | struct msp_state *state = i2c_get_clientdata(client); | 1003 | struct msp_state *state = i2c_get_clientdata(client); |
924 | |||
925 | int status = msp_read_dem(client, 0x0200); | 1004 | int status = msp_read_dem(client, 0x0200); |
926 | int is_bilingual = status & 0x100; | 1005 | int is_bilingual = status & 0x100; |
927 | int is_stereo = status & 0x40; | 1006 | int is_stereo = status & 0x40; |
1007 | int oldrx = state->rxsubchans; | ||
928 | 1008 | ||
929 | state->rxsubchans = 0; | 1009 | state->rxsubchans = 0; |
930 | if (is_stereo) | 1010 | if (is_stereo) |
@@ -932,42 +1012,31 @@ static void msp34xxg_detect_stereo(struct i2c_client *client) | |||
932 | else | 1012 | else |
933 | state->rxsubchans = V4L2_TUNER_SUB_MONO; | 1013 | state->rxsubchans = V4L2_TUNER_SUB_MONO; |
934 | if (is_bilingual) { | 1014 | if (is_bilingual) { |
935 | state->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; | 1015 | if (state->std == 0x20) |
936 | /* I'm supposed to check whether it's SAP or not | 1016 | state->rxsubchans |= V4L2_TUNER_SUB_SAP; |
937 | * and set only LANG2/SAP in this case. Yet, the MSP | 1017 | else |
938 | * does a lot of work to hide this and handle everything | 1018 | state->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; |
939 | * the same way. I don't want to work around it so unless | ||
940 | * this is a problem, I'll handle SAP just like lang1/lang2. | ||
941 | */ | ||
942 | } | 1019 | } |
943 | v4l_dbg(1, msp_debug, client, "status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n", | 1020 | v4l_dbg(1, msp_debug, client, "status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n", |
944 | status, is_stereo, is_bilingual, state->rxsubchans); | 1021 | status, is_stereo, is_bilingual, state->rxsubchans); |
1022 | return (oldrx != state->rxsubchans); | ||
945 | } | 1023 | } |
946 | 1024 | ||
947 | static void msp34xxg_set_audmode(struct i2c_client *client) | 1025 | static void msp34xxg_set_audmode(struct i2c_client *client) |
948 | { | 1026 | { |
949 | struct msp_state *state = i2c_get_clientdata(client); | 1027 | struct msp_state *state = i2c_get_clientdata(client); |
950 | int source; | ||
951 | 1028 | ||
952 | switch (state->audmode) { | 1029 | if (state->std == 0x20) { |
953 | case V4L2_TUNER_MODE_MONO: | 1030 | if ((state->rxsubchans & V4L2_TUNER_SUB_SAP) && |
954 | source = 0; /* mono only */ | 1031 | (state->audmode == V4L2_TUNER_MODE_STEREO || |
955 | break; | 1032 | state->audmode == V4L2_TUNER_MODE_LANG2)) { |
956 | case V4L2_TUNER_MODE_STEREO: | 1033 | msp_write_dem(client, 0x20, 0x21); |
957 | source = 1; /* stereo or A|B, see comment in msp34xxg_get_v4l2_stereo() */ | 1034 | } else { |
958 | /* problem: that could also mean 2 (scart input) */ | 1035 | msp_write_dem(client, 0x20, 0x20); |
959 | break; | 1036 | } |
960 | case V4L2_TUNER_MODE_LANG1: | ||
961 | source = 3; /* stereo or A */ | ||
962 | break; | ||
963 | case V4L2_TUNER_MODE_LANG2: | ||
964 | source = 4; /* stereo or B */ | ||
965 | break; | ||
966 | default: | ||
967 | source = 1; | ||
968 | break; | ||
969 | } | 1037 | } |
970 | msp34xxg_set_source(client, source); | 1038 | |
1039 | msp34xxg_set_sources(client); | ||
971 | } | 1040 | } |
972 | 1041 | ||
973 | void msp_set_audmode(struct i2c_client *client) | 1042 | void msp_set_audmode(struct i2c_client *client) |
@@ -977,7 +1046,6 @@ void msp_set_audmode(struct i2c_client *client) | |||
977 | switch (state->opmode) { | 1046 | switch (state->opmode) { |
978 | case OPMODE_MANUAL: | 1047 | case OPMODE_MANUAL: |
979 | case OPMODE_AUTODETECT: | 1048 | case OPMODE_AUTODETECT: |
980 | state->watch_stereo = 0; | ||
981 | msp3400c_set_audmode(client); | 1049 | msp3400c_set_audmode(client); |
982 | break; | 1050 | break; |
983 | case OPMODE_AUTOSELECT: | 1051 | case OPMODE_AUTOSELECT: |
@@ -986,18 +1054,17 @@ void msp_set_audmode(struct i2c_client *client) | |||
986 | } | 1054 | } |
987 | } | 1055 | } |
988 | 1056 | ||
989 | void msp_detect_stereo(struct i2c_client *client) | 1057 | int msp_detect_stereo(struct i2c_client *client) |
990 | { | 1058 | { |
991 | struct msp_state *state = i2c_get_clientdata(client); | 1059 | struct msp_state *state = i2c_get_clientdata(client); |
992 | 1060 | ||
993 | switch (state->opmode) { | 1061 | switch (state->opmode) { |
994 | case OPMODE_MANUAL: | 1062 | case OPMODE_MANUAL: |
995 | case OPMODE_AUTODETECT: | 1063 | case OPMODE_AUTODETECT: |
996 | msp3400c_detect_stereo(client); | 1064 | return msp3400c_detect_stereo(client); |
997 | break; | ||
998 | case OPMODE_AUTOSELECT: | 1065 | case OPMODE_AUTOSELECT: |
999 | msp34xxg_detect_stereo(client); | 1066 | return msp34xxg_detect_stereo(client); |
1000 | break; | ||
1001 | } | 1067 | } |
1068 | return 0; | ||
1002 | } | 1069 | } |
1003 | 1070 | ||