diff options
Diffstat (limited to 'drivers/media/video/msp3400-driver.c')
-rw-r--r-- | drivers/media/video/msp3400-driver.c | 249 |
1 files changed, 43 insertions, 206 deletions
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index 11ea9765769c..c40e8ba9a2ea 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c | |||
@@ -53,10 +53,11 @@ | |||
53 | #include <linux/videodev.h> | 53 | #include <linux/videodev.h> |
54 | #include <linux/videodev2.h> | 54 | #include <linux/videodev2.h> |
55 | #include <media/v4l2-common.h> | 55 | #include <media/v4l2-common.h> |
56 | #include <media/audiochip.h> | 56 | #include <media/tvaudio.h> |
57 | #include <media/msp3400.h> | ||
57 | #include <linux/kthread.h> | 58 | #include <linux/kthread.h> |
58 | #include <linux/suspend.h> | 59 | #include <linux/suspend.h> |
59 | #include "msp3400.h" | 60 | #include "msp3400-driver.h" |
60 | 61 | ||
61 | /* ---------------------------------------------------------------------- */ | 62 | /* ---------------------------------------------------------------------- */ |
62 | 63 | ||
@@ -245,31 +246,31 @@ int msp_write_dsp(struct i2c_client *client, int addr, int val) | |||
245 | * ----------------------------------------------------------------------- */ | 246 | * ----------------------------------------------------------------------- */ |
246 | 247 | ||
247 | static int scarts[3][9] = { | 248 | static int scarts[3][9] = { |
248 | /* MASK IN1 IN2 IN1_DA IN2_DA IN3 IN4 MONO MUTE */ | 249 | /* MASK IN1 IN2 IN3 IN4 IN1_DA IN2_DA MONO MUTE */ |
249 | /* SCART DSP Input select */ | 250 | /* SCART DSP Input select */ |
250 | { 0x0320, 0x0000, 0x0200, -1, -1, 0x0300, 0x0020, 0x0100, 0x0320 }, | 251 | { 0x0320, 0x0000, 0x0200, 0x0300, 0x0020, -1, -1, 0x0100, 0x0320 }, |
251 | /* SCART1 Output select */ | 252 | /* SCART1 Output select */ |
252 | { 0x0c40, 0x0440, 0x0400, 0x0c00, 0x0040, 0x0000, 0x0840, 0x0800, 0x0c40 }, | 253 | { 0x0c40, 0x0440, 0x0400, 0x0000, 0x0840, 0x0c00, 0x0040, 0x0800, 0x0c40 }, |
253 | /* SCART2 Output select */ | 254 | /* SCART2 Output select */ |
254 | { 0x3080, 0x1000, 0x1080, 0x0000, 0x0080, 0x2080, 0x3080, 0x2000, 0x3000 }, | 255 | { 0x3080, 0x1000, 0x1080, 0x2080, 0x3080, 0x0000, 0x0080, 0x2000, 0x3000 }, |
255 | }; | 256 | }; |
256 | 257 | ||
257 | static char *scart_names[] = { | 258 | static char *scart_names[] = { |
258 | "mask", "in1", "in2", "in1 da", "in2 da", "in3", "in4", "mono", "mute" | 259 | "in1", "in2", "in3", "in4", "in1 da", "in2 da", "mono", "mute" |
259 | }; | 260 | }; |
260 | 261 | ||
261 | void msp_set_scart(struct i2c_client *client, int in, int out) | 262 | void msp_set_scart(struct i2c_client *client, int in, int out) |
262 | { | 263 | { |
263 | struct msp_state *state = i2c_get_clientdata(client); | 264 | struct msp_state *state = i2c_get_clientdata(client); |
264 | 265 | ||
265 | state->in_scart=in; | 266 | state->in_scart = in; |
266 | 267 | ||
267 | if (in >= 1 && in <= 8 && out >= 0 && out <= 2) { | 268 | if (in >= 0 && in <= 7 && out >= 0 && out <= 2) { |
268 | if (-1 == scarts[out][in]) | 269 | if (-1 == scarts[out][in + 1]) |
269 | return; | 270 | return; |
270 | 271 | ||
271 | state->acb &= ~scarts[out][SCART_MASK]; | 272 | state->acb &= ~scarts[out][0]; |
272 | state->acb |= scarts[out][in]; | 273 | state->acb |= scarts[out][in + 1]; |
273 | } else | 274 | } else |
274 | state->acb = 0xf60; /* Mute Input and SCART 1 Output */ | 275 | state->acb = 0xf60; /* Mute Input and SCART 1 Output */ |
275 | 276 | ||
@@ -336,37 +337,6 @@ void msp_set_audio(struct i2c_client *client) | |||
336 | msp_write_dsp(client, 0x0033, loudness); | 337 | msp_write_dsp(client, 0x0033, loudness); |
337 | } | 338 | } |
338 | 339 | ||
339 | int msp_modus(struct i2c_client *client) | ||
340 | { | ||
341 | struct msp_state *state = i2c_get_clientdata(client); | ||
342 | |||
343 | if (state->radio) { | ||
344 | v4l_dbg(1, msp_debug, client, "video mode selected to Radio\n"); | ||
345 | return 0x0003; | ||
346 | } | ||
347 | |||
348 | if (state->v4l2_std & V4L2_STD_PAL) { | ||
349 | v4l_dbg(1, msp_debug, client, "video mode selected to PAL\n"); | ||
350 | |||
351 | #if 1 | ||
352 | /* experimental: not sure this works with all chip versions */ | ||
353 | return 0x7003; | ||
354 | #else | ||
355 | /* previous value, try this if it breaks ... */ | ||
356 | return 0x1003; | ||
357 | #endif | ||
358 | } | ||
359 | if (state->v4l2_std & V4L2_STD_NTSC) { | ||
360 | v4l_dbg(1, msp_debug, client, "video mode selected to NTSC\n"); | ||
361 | return 0x2003; | ||
362 | } | ||
363 | if (state->v4l2_std & V4L2_STD_SECAM) { | ||
364 | v4l_dbg(1, msp_debug, client, "video mode selected to SECAM\n"); | ||
365 | return 0x0003; | ||
366 | } | ||
367 | return 0x0003; | ||
368 | } | ||
369 | |||
370 | /* ------------------------------------------------------------------------ */ | 340 | /* ------------------------------------------------------------------------ */ |
371 | 341 | ||
372 | 342 | ||
@@ -585,51 +555,11 @@ static int msp_set_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) | |||
585 | static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) | 555 | static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) |
586 | { | 556 | { |
587 | struct msp_state *state = i2c_get_clientdata(client); | 557 | struct msp_state *state = i2c_get_clientdata(client); |
588 | u16 *sarg = arg; | ||
589 | int scart = 0; | ||
590 | 558 | ||
591 | if (msp_debug >= 2) | 559 | if (msp_debug >= 2) |
592 | v4l_i2c_print_ioctl(client, cmd); | 560 | v4l_i2c_print_ioctl(client, cmd); |
593 | 561 | ||
594 | switch (cmd) { | 562 | switch (cmd) { |
595 | case AUDC_SET_INPUT: | ||
596 | if (*sarg == state->input) | ||
597 | break; | ||
598 | state->input = *sarg; | ||
599 | switch (*sarg) { | ||
600 | case AUDIO_RADIO: | ||
601 | /* Hauppauge uses IN2 for the radio */ | ||
602 | state->mode = MSP_MODE_FM_RADIO; | ||
603 | scart = SCART_IN2; | ||
604 | break; | ||
605 | case AUDIO_EXTERN_1: | ||
606 | /* IN1 is often used for external input ... */ | ||
607 | state->mode = MSP_MODE_EXTERN; | ||
608 | scart = SCART_IN1; | ||
609 | break; | ||
610 | case AUDIO_EXTERN_2: | ||
611 | /* ... sometimes it is IN2 through ;) */ | ||
612 | state->mode = MSP_MODE_EXTERN; | ||
613 | scart = SCART_IN2; | ||
614 | break; | ||
615 | case AUDIO_TUNER: | ||
616 | state->mode = -1; | ||
617 | break; | ||
618 | default: | ||
619 | if (*sarg & AUDIO_MUTE) | ||
620 | msp_set_scart(client, SCART_MUTE, 0); | ||
621 | break; | ||
622 | } | ||
623 | if (scart) { | ||
624 | state->rxsubchans = V4L2_TUNER_SUB_STEREO; | ||
625 | msp_set_scart(client, scart, 0); | ||
626 | msp_write_dsp(client, 0x000d, 0x1900); | ||
627 | if (state->opmode != OPMODE_AUTOSELECT) | ||
628 | msp_set_audmode(client); | ||
629 | } | ||
630 | msp_wake_thread(client); | ||
631 | break; | ||
632 | |||
633 | case AUDC_SET_RADIO: | 563 | case AUDC_SET_RADIO: |
634 | if (state->radio) | 564 | if (state->radio) |
635 | return 0; | 565 | return 0; |
@@ -692,6 +622,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) | |||
692 | 622 | ||
693 | if (va->mode != 0 && state->radio == 0) { | 623 | if (va->mode != 0 && state->radio == 0) { |
694 | state->audmode = msp_mode_v4l1_to_v4l2(va->mode); | 624 | state->audmode = msp_mode_v4l1_to_v4l2(va->mode); |
625 | msp_set_audmode(client); | ||
695 | } | 626 | } |
696 | break; | 627 | break; |
697 | } | 628 | } |
@@ -728,15 +659,6 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) | |||
728 | break; | 659 | break; |
729 | } | 660 | } |
730 | 661 | ||
731 | /* msp34xx specific */ | ||
732 | case MSP_SET_MATRIX: | ||
733 | { | ||
734 | struct msp_matrix *mspm = arg; | ||
735 | |||
736 | msp_set_scart(client, mspm->input, mspm->output); | ||
737 | break; | ||
738 | } | ||
739 | |||
740 | /* --- v4l2 ioctls --- */ | 662 | /* --- v4l2 ioctls --- */ |
741 | case VIDIOC_S_STD: | 663 | case VIDIOC_S_STD: |
742 | { | 664 | { |
@@ -750,90 +672,34 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) | |||
750 | return 0; | 672 | return 0; |
751 | } | 673 | } |
752 | 674 | ||
753 | case VIDIOC_ENUMINPUT: | 675 | case VIDIOC_INT_G_AUDIO_ROUTING: |
754 | { | ||
755 | struct v4l2_input *i = arg; | ||
756 | |||
757 | if (i->index != 0) | ||
758 | return -EINVAL; | ||
759 | |||
760 | i->type = V4L2_INPUT_TYPE_TUNER; | ||
761 | switch (i->index) { | ||
762 | case AUDIO_RADIO: | ||
763 | strcpy(i->name, "Radio"); | ||
764 | break; | ||
765 | case AUDIO_EXTERN_1: | ||
766 | strcpy(i->name, "Extern 1"); | ||
767 | break; | ||
768 | case AUDIO_EXTERN_2: | ||
769 | strcpy(i->name, "Extern 2"); | ||
770 | break; | ||
771 | case AUDIO_TUNER: | ||
772 | strcpy(i->name, "Television"); | ||
773 | break; | ||
774 | default: | ||
775 | return -EINVAL; | ||
776 | } | ||
777 | return 0; | ||
778 | } | ||
779 | |||
780 | case VIDIOC_G_AUDIO: | ||
781 | { | 676 | { |
782 | struct v4l2_audio *a = arg; | 677 | struct v4l2_routing *rt = arg; |
783 | 678 | ||
784 | memset(a, 0, sizeof(*a)); | 679 | *rt = state->routing; |
785 | |||
786 | switch (a->index) { | ||
787 | case AUDIO_RADIO: | ||
788 | strcpy(a->name, "Radio"); | ||
789 | break; | ||
790 | case AUDIO_EXTERN_1: | ||
791 | strcpy(a->name, "Extern 1"); | ||
792 | break; | ||
793 | case AUDIO_EXTERN_2: | ||
794 | strcpy(a->name, "Extern 2"); | ||
795 | break; | ||
796 | case AUDIO_TUNER: | ||
797 | strcpy(a->name, "Television"); | ||
798 | break; | ||
799 | default: | ||
800 | return -EINVAL; | ||
801 | } | ||
802 | |||
803 | a->capability = V4L2_AUDCAP_STEREO; | ||
804 | a->mode = 0; /* TODO: add support for AVL */ | ||
805 | break; | 680 | break; |
806 | } | 681 | } |
807 | 682 | ||
808 | case VIDIOC_S_AUDIO: | 683 | case VIDIOC_INT_S_AUDIO_ROUTING: |
809 | { | 684 | { |
810 | struct v4l2_audio *sarg = arg; | 685 | struct v4l2_routing *rt = arg; |
811 | 686 | int tuner = (rt->input >> 3) & 1; | |
812 | switch (sarg->index) { | 687 | int sc_in = rt->input & 0x7; |
813 | case AUDIO_RADIO: | 688 | int sc1_out = rt->output & 0xf; |
814 | /* Hauppauge uses IN2 for the radio */ | 689 | int sc2_out = (rt->output >> 4) & 0xf; |
815 | state->mode = MSP_MODE_FM_RADIO; | 690 | u16 val; |
816 | scart = SCART_IN2; | 691 | |
817 | break; | 692 | state->routing = *rt; |
818 | case AUDIO_EXTERN_1: | 693 | if (state->opmode == OPMODE_AUTOSELECT) { |
819 | /* IN1 is often used for external input ... */ | 694 | val = msp_read_dem(client, 0x30) & ~0x100; |
820 | state->mode = MSP_MODE_EXTERN; | 695 | msp_write_dem(client, 0x30, val | (tuner ? 0x100 : 0)); |
821 | scart = SCART_IN1; | 696 | } else { |
822 | break; | 697 | val = msp_read_dem(client, 0xbb) & ~0x100; |
823 | case AUDIO_EXTERN_2: | 698 | msp_write_dem(client, 0xbb, val | (tuner ? 0x100 : 0)); |
824 | /* ... sometimes it is IN2 through ;) */ | ||
825 | state->mode = MSP_MODE_EXTERN; | ||
826 | scart = SCART_IN2; | ||
827 | break; | ||
828 | case AUDIO_TUNER: | ||
829 | state->mode = -1; | ||
830 | break; | ||
831 | } | ||
832 | if (scart) { | ||
833 | state->rxsubchans = V4L2_TUNER_SUB_STEREO; | ||
834 | msp_set_scart(client, scart, 0); | ||
835 | msp_write_dsp(client, 0x000d, 0x1900); | ||
836 | } | 699 | } |
700 | msp_set_scart(client, sc_in, 0); | ||
701 | msp_set_scart(client, sc1_out, 1); | ||
702 | msp_set_scart(client, sc2_out, 2); | ||
837 | msp_set_audmode(client); | 703 | msp_set_audmode(client); |
838 | msp_wake_thread(client); | 704 | msp_wake_thread(client); |
839 | break; | 705 | break; |
@@ -866,42 +732,6 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) | |||
866 | break; | 732 | break; |
867 | } | 733 | } |
868 | 734 | ||
869 | case VIDIOC_G_AUDOUT: | ||
870 | { | ||
871 | struct v4l2_audioout *a = (struct v4l2_audioout *)arg; | ||
872 | int idx = a->index; | ||
873 | |||
874 | memset(a, 0, sizeof(*a)); | ||
875 | |||
876 | switch (idx) { | ||
877 | case 0: | ||
878 | strcpy(a->name, "Scart1 Out"); | ||
879 | break; | ||
880 | case 1: | ||
881 | strcpy(a->name, "Scart2 Out"); | ||
882 | break; | ||
883 | case 2: | ||
884 | strcpy(a->name, "I2S Out"); | ||
885 | break; | ||
886 | default: | ||
887 | return -EINVAL; | ||
888 | } | ||
889 | break; | ||
890 | } | ||
891 | |||
892 | case VIDIOC_S_AUDOUT: | ||
893 | { | ||
894 | struct v4l2_audioout *a = (struct v4l2_audioout *)arg; | ||
895 | |||
896 | if (a->index < 0 || a->index > 2) | ||
897 | return -EINVAL; | ||
898 | |||
899 | v4l_dbg(1, msp_debug, client, "Setting audio out on msp34xx to input %i\n", a->index); | ||
900 | msp_set_scart(client, state->in_scart, a->index + 1); | ||
901 | |||
902 | break; | ||
903 | } | ||
904 | |||
905 | case VIDIOC_INT_I2S_CLOCK_FREQ: | 735 | case VIDIOC_INT_I2S_CLOCK_FREQ: |
906 | { | 736 | { |
907 | u32 *a = (u32 *)arg; | 737 | u32 *a = (u32 *)arg; |
@@ -979,12 +809,16 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) | |||
979 | (state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono", | 809 | (state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono", |
980 | (state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : ""); | 810 | (state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : ""); |
981 | } else { | 811 | } else { |
982 | v4l_info(client, "Mode: %s\n", p); | 812 | if (state->opmode == OPMODE_AUTODETECT) |
813 | v4l_info(client, "Mode: %s\n", p); | ||
983 | v4l_info(client, "Standard: %s (%s%s)\n", | 814 | v4l_info(client, "Standard: %s (%s%s)\n", |
984 | msp_standard_std_name(state->std), | 815 | msp_standard_std_name(state->std), |
985 | (state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono", | 816 | (state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono", |
986 | (state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : ""); | 817 | (state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : ""); |
987 | } | 818 | } |
819 | v4l_info(client, "Audmode: 0x%04x\n", state->audmode); | ||
820 | v4l_info(client, "Routing: 0x%08x (input) 0x%08x (output)\n", | ||
821 | state->routing.input, state->routing.output); | ||
988 | v4l_info(client, "ACB: 0x%04x\n", state->acb); | 822 | v4l_info(client, "ACB: 0x%04x\n", state->acb); |
989 | break; | 823 | break; |
990 | } | 824 | } |
@@ -1063,6 +897,9 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) | |||
1063 | state->muted = 0; | 897 | state->muted = 0; |
1064 | state->i2s_mode = 0; | 898 | state->i2s_mode = 0; |
1065 | init_waitqueue_head(&state->wq); | 899 | init_waitqueue_head(&state->wq); |
900 | /* These are the reset input/output positions */ | ||
901 | state->routing.input = MSP_INPUT_DEFAULT; | ||
902 | state->routing.output = MSP_OUTPUT_DEFAULT; | ||
1066 | 903 | ||
1067 | state->rev1 = msp_read_dsp(client, 0x1e); | 904 | state->rev1 = msp_read_dsp(client, 0x1e); |
1068 | if (state->rev1 != -1) | 905 | if (state->rev1 != -1) |