aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitri Belimov <d.belimov@gmail.com>2011-02-17 20:11:05 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-03-21 19:32:20 -0400
commit8aff8ba95155dff265de5ea6f5d5d92caa7bc728 (patch)
tree75cea34d0c2d7d1373143c95610bc81fe3c9482f
parent6ca000479fdb80b9059b69c67c82f8dc0d5f5d47 (diff)
[media] tm6000: add radio support to the driver
Changes: Add function tm6000_set_reg_mask for change some bits in regs. Very usefull, simplify some code with this function. Add control mute Add control volume Add control audio input MUX Add support radio Radio works well. TV works too Known bugs: The programm gnomeradio can't set freq for radio, it use old v4l API. Audio over USB works via arecord. The programm mplayer can set freq but no any audio mplayer -v -rawaudio rate=48000 radio://105.2/capture driver=v4l2:alsa:adevice=hw.1,0:amode=1:audiorate=48000:forceaudio:immediatemode=0 When start watch TV very shortly after radio the kernel crashed hardly. Didn't stop all USB URBs, need some time for stop. [mchehab@redhat.com: fix merge conflicts] Signed-off-by: Beholder Intl. Ltd. Dmitry Belimov <d.belimov@gmail.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/staging/tm6000/tm6000-alsa.c13
-rw-r--r--drivers/staging/tm6000/tm6000-cards.c11
-rw-r--r--drivers/staging/tm6000/tm6000-core.c260
-rw-r--r--drivers/staging/tm6000/tm6000-stds.c33
-rw-r--r--drivers/staging/tm6000/tm6000-video.c327
-rw-r--r--drivers/staging/tm6000/tm6000.h23
6 files changed, 566 insertions, 101 deletions
diff --git a/drivers/staging/tm6000/tm6000-alsa.c b/drivers/staging/tm6000/tm6000-alsa.c
index 184cc505ed86..acb03172a887 100644
--- a/drivers/staging/tm6000/tm6000-alsa.c
+++ b/drivers/staging/tm6000/tm6000-alsa.c
@@ -76,14 +76,11 @@ MODULE_PARM_DESC(debug, "enable debug messages");
76static int _tm6000_start_audio_dma(struct snd_tm6000_card *chip) 76static int _tm6000_start_audio_dma(struct snd_tm6000_card *chip)
77{ 77{
78 struct tm6000_core *core = chip->core; 78 struct tm6000_core *core = chip->core;
79 int val;
80 79
81 dprintk(1, "Starting audio DMA\n"); 80 dprintk(1, "Starting audio DMA\n");
82 81
83 /* Enables audio */ 82 /* Enables audio */
84 val = tm6000_get_reg(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0x0); 83 tm6000_set_reg_mask(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0x40, 0x40);
85 val |= 0x20;
86 tm6000_set_reg(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val);
87 84
88 tm6000_set_audio_bitrate(core, 48000); 85 tm6000_set_audio_bitrate(core, 48000);
89 86
@@ -98,13 +95,11 @@ static int _tm6000_start_audio_dma(struct snd_tm6000_card *chip)
98static int _tm6000_stop_audio_dma(struct snd_tm6000_card *chip) 95static int _tm6000_stop_audio_dma(struct snd_tm6000_card *chip)
99{ 96{
100 struct tm6000_core *core = chip->core; 97 struct tm6000_core *core = chip->core;
101 int val; 98
102 dprintk(1, "Stopping audio DMA\n"); 99 dprintk(1, "Stopping audio DMA\n");
103 100
104 /* Enables audio */ 101 /* Disables audio */
105 val = tm6000_get_reg(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0x0); 102 tm6000_set_reg_mask(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0x00, 0x40);
106 val &= ~0x20;
107 tm6000_set_reg(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val);
108 103
109 tm6000_set_reg(core, TM6010_REQ08_R01_A_INIT, 0); 104 tm6000_set_reg(core, TM6010_REQ08_R01_A_INIT, 0);
110 105
diff --git a/drivers/staging/tm6000/tm6000-cards.c b/drivers/staging/tm6000/tm6000-cards.c
index 290037eecd61..a356ba7aa77c 100644
--- a/drivers/staging/tm6000/tm6000-cards.c
+++ b/drivers/staging/tm6000/tm6000-cards.c
@@ -66,6 +66,8 @@ struct tm6000_board {
66 char *name; 66 char *name;
67 67
68 struct tm6000_capabilities caps; 68 struct tm6000_capabilities caps;
69 enum tm6000_inaudio aradio;
70 enum tm6000_inaudio avideo;
69 71
70 enum tm6000_devtype type; /* variant of the chipset */ 72 enum tm6000_devtype type; /* variant of the chipset */
71 int tuner_type; /* type of the tuner */ 73 int tuner_type; /* type of the tuner */
@@ -230,6 +232,8 @@ struct tm6000_board tm6000_boards[] = {
230 .tuner_addr = 0xc2 >> 1, 232 .tuner_addr = 0xc2 >> 1,
231 .demod_addr = 0x1e >> 1, 233 .demod_addr = 0x1e >> 1,
232 .type = TM6010, 234 .type = TM6010,
235 .avideo = TM6000_AIP_SIF1,
236 .aradio = TM6000_AIP_LINE1,
233 .caps = { 237 .caps = {
234 .has_tuner = 1, 238 .has_tuner = 1,
235 .has_dvb = 1, 239 .has_dvb = 1,
@@ -248,6 +252,8 @@ struct tm6000_board tm6000_boards[] = {
248 .tuner_type = TUNER_XC5000, 252 .tuner_type = TUNER_XC5000,
249 .tuner_addr = 0xc2 >> 1, 253 .tuner_addr = 0xc2 >> 1,
250 .type = TM6010, 254 .type = TM6010,
255 .avideo = TM6000_AIP_SIF1,
256 .aradio = TM6000_AIP_LINE1,
251 .caps = { 257 .caps = {
252 .has_tuner = 1, 258 .has_tuner = 1,
253 .has_dvb = 0, 259 .has_dvb = 0,
@@ -693,13 +699,12 @@ static void tm6000_config_tuner(struct tm6000_core *dev)
693 struct xc5000_config ctl = { 699 struct xc5000_config ctl = {
694 .i2c_address = dev->tuner_addr, 700 .i2c_address = dev->tuner_addr,
695 .if_khz = 4570, 701 .if_khz = 4570,
696 .radio_input = XC5000_RADIO_FM1, 702 .radio_input = XC5000_RADIO_FM1_MONO,
697 }; 703 };
698 704
699 xc5000_cfg.tuner = TUNER_XC5000; 705 xc5000_cfg.tuner = TUNER_XC5000;
700 xc5000_cfg.priv = &ctl; 706 xc5000_cfg.priv = &ctl;
701 707
702
703 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, 708 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config,
704 &xc5000_cfg); 709 &xc5000_cfg);
705 } 710 }
@@ -732,6 +737,8 @@ static int tm6000_init_dev(struct tm6000_core *dev)
732 737
733 dev->caps = tm6000_boards[dev->model].caps; 738 dev->caps = tm6000_boards[dev->model].caps;
734 739
740 dev->avideo = tm6000_boards[dev->model].avideo;
741 dev->aradio = tm6000_boards[dev->model].aradio;
735 /* initialize hardware */ 742 /* initialize hardware */
736 rc = tm6000_init(dev); 743 rc = tm6000_init(dev);
737 if (rc < 0) 744 if (rc < 0)
diff --git a/drivers/staging/tm6000/tm6000-core.c b/drivers/staging/tm6000/tm6000-core.c
index 5162cd4a8288..778e53413afb 100644
--- a/drivers/staging/tm6000/tm6000-core.c
+++ b/drivers/staging/tm6000/tm6000-core.c
@@ -116,6 +116,29 @@ int tm6000_get_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index)
116} 116}
117EXPORT_SYMBOL_GPL(tm6000_get_reg); 117EXPORT_SYMBOL_GPL(tm6000_get_reg);
118 118
119int tm6000_set_reg_mask(struct tm6000_core *dev, u8 req, u16 value,
120 u16 index, u16 mask)
121{
122 int rc;
123 u8 buf[1];
124 u8 new_index;
125
126 rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
127 value, index, buf, 1);
128
129 if (rc < 0)
130 return rc;
131
132 new_index = (buf[0] & ~mask) | (index & mask);
133
134 if (new_index == index)
135 return 0;
136
137 return tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR,
138 req, value, new_index, NULL, 0);
139}
140EXPORT_SYMBOL_GPL(tm6000_set_reg_mask);
141
119int tm6000_get_reg16(struct tm6000_core *dev, u8 req, u16 value, u16 index) 142int tm6000_get_reg16(struct tm6000_core *dev, u8 req, u16 value, u16 index)
120{ 143{
121 int rc; 144 int rc;
@@ -245,17 +268,12 @@ int tm6000_init_analog_mode(struct tm6000_core *dev)
245 struct v4l2_frequency f; 268 struct v4l2_frequency f;
246 269
247 if (dev->dev_type == TM6010) { 270 if (dev->dev_type == TM6010) {
248 int val;
249
250 /* Enable video */ 271 /* Enable video */
251 val = tm6000_get_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0);
252 val |= 0x60;
253 tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val);
254 val = tm6000_get_reg(dev,
255 TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0);
256 val &= ~0x40;
257 tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, val);
258 272
273 tm6000_set_reg_mask(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF,
274 0x60, 0x60);
275 tm6000_set_reg_mask(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE,
276 0x00, 0x40);
259 tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc); 277 tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc);
260 278
261 } else { 279 } else {
@@ -471,6 +489,14 @@ struct reg_init tm6010_init_tab[] = {
471 { TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xf0 }, 489 { TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xf0 },
472 { TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2 }, 490 { TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2 },
473 { TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x60 }, 491 { TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x60 },
492 { TM6010_REQ08_R03_A_AUTO_GAIN_CTRL, 0x00},
493 { TM6010_REQ08_R04_A_SIF_AMP_CTRL, 0x80},
494 { TM6010_REQ08_R0C_A_ASD_THRES2, 0x0a},
495 { TM6010_REQ08_R0D_A_AMD_THRES, 0x40},
496 { TM6010_REQ08_R1A_A_NICAM_SER_MAX, 0x64},
497 { TM6010_REQ08_R1B_A_NICAM_SER_MIN, 0x20},
498 { TM6010_REQ08_R16_A_AGC_GAIN_MAX, 0xfe},
499 { TM6010_REQ08_R17_A_AGC_GAIN_MIN, 0x01},
474 { TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc }, 500 { TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc },
475 501
476 { TM6010_REQ07_R3F_RESET, 0x01 }, 502 { TM6010_REQ07_R3F_RESET, 0x01 },
@@ -591,51 +617,213 @@ int tm6000_init(struct tm6000_core *dev)
591 617
592int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate) 618int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate)
593{ 619{
594 int val; 620 int val = 0;
621 u8 areg_f0 = 0x60; /* ADC MCLK = 250 Fs */
622 u8 areg_0a = 0x91; /* SIF 48KHz */
623
624 switch (bitrate) {
625 case 48000:
626 areg_f0 = 0x60; /* ADC MCLK = 250 Fs */
627 areg_0a = 0x91; /* SIF 48KHz */
628 dev->audio_bitrate = bitrate;
629 break;
630 case 32000:
631 areg_f0 = 0x00; /* ADC MCLK = 375 Fs */
632 areg_0a = 0x90; /* SIF 32KHz */
633 dev->audio_bitrate = bitrate;
634 break;
635 default:
636 return -EINVAL;
637 }
638
595 639
596 /* enable I2S, if we use sif or external I2S device */ 640 /* enable I2S, if we use sif or external I2S device */
597 if (dev->dev_type == TM6010) { 641 if (dev->dev_type == TM6010) {
598 val = tm6000_get_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, 0); 642 val = tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, areg_0a);
599 if (val < 0)
600 return val;
601 val = (val & 0xf0) | 0x1; /* 48 kHz, not muted */
602 val = tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, val);
603 if (val < 0) 643 if (val < 0)
604 return val; 644 return val;
605 }
606 645
607 /* different reg's to set audio bitrate */ 646 val = tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
608 if (dev->dev_type == TM6010) { 647 areg_f0, 0xf0);
609 val = tm6000_get_reg(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
610 0x0);
611 if (val < 0) 648 if (val < 0)
612 return val; 649 return val;
613 } else { 650 } else {
614 val = tm6000_get_reg(dev, TM6000_REQ07_REB_VADC_AADC_MODE, 0x0); 651 val = tm6000_set_reg_mask(dev, TM6000_REQ07_REB_VADC_AADC_MODE,
652 areg_f0, 0xf0);
615 if (val < 0) 653 if (val < 0)
616 return val; 654 return val;
617 } 655 }
656 return 0;
657}
658EXPORT_SYMBOL_GPL(tm6000_set_audio_bitrate);
618 659
619 val &= 0x0f; /* Preserve the audio input control bits */ 660int tm6000_set_audio_input(struct tm6000_core *dev, enum tm6000_inaudio ainp)
620 switch (bitrate) { 661{
621 case 44100: 662 if (dev->dev_type == TM6010) {
622 val |= 0xd0; 663 /* Audio crossbar setting, default SIF1 */
623 dev->audio_bitrate = bitrate; 664 u8 areg_f0 = 0x03;
665
666 switch (ainp) {
667 case TM6000_AIP_SIF1:
668 case TM6000_AIP_SIF2:
669 areg_f0 = 0x03;
670 break;
671 case TM6000_AIP_LINE1:
672 areg_f0 = 0x00;
673 break;
674 case TM6000_AIP_LINE2:
675 areg_f0 = 0x08;
676 break;
677 default:
678 return 0;
679 break;
680 }
681 /* Set audio input crossbar */
682 tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
683 areg_f0, 0x0f);
684 } else {
685 /* Audio setting, default LINE1 */
686 u8 areg_eb = 0x00;
687
688 switch (ainp) {
689 case TM6000_AIP_LINE1:
690 areg_eb = 0x00;
691 break;
692 case TM6000_AIP_LINE2:
693 areg_eb = 0x04;
694 break;
695 default:
696 return 0;
697 break;
698 }
699 /* Set audio input */
700 tm6000_set_reg_mask(dev, TM6000_REQ07_REB_VADC_AADC_MODE,
701 areg_eb, 0x0f);
702 }
703 return 0;
704}
705EXPORT_SYMBOL_GPL(tm6000_set_audio_input);
706
707void tm6010_set_mute_sif(struct tm6000_core *dev, u8 mute)
708{
709 u8 mute_reg = 0;
710
711 if (mute)
712 mute_reg = 0x08;
713
714 tm6000_set_reg_mask(dev, TM6010_REQ08_R0A_A_I2S_MOD, mute_reg, 0x08);
715}
716
717void tm6010_set_mute_adc(struct tm6000_core *dev, u8 mute)
718{
719 u8 mute_reg = 0;
720
721 if (mute)
722 mute_reg = 0x20;
723
724 if (dev->dev_type == TM6010) {
725 tm6000_set_reg_mask(dev, TM6010_REQ08_RF2_LEFT_CHANNEL_VOL,
726 mute_reg, 0x20);
727 tm6000_set_reg_mask(dev, TM6010_REQ08_RF3_RIGHT_CHANNEL_VOL,
728 mute_reg, 0x20);
729 } else {
730 tm6000_set_reg_mask(dev, TM6000_REQ07_REC_VADC_AADC_LVOL,
731 mute_reg, 0x20);
732 tm6000_set_reg_mask(dev, TM6000_REQ07_RED_VADC_AADC_RVOL,
733 mute_reg, 0x20);
734 }
735}
736
737int tm6000_tvaudio_set_mute(struct tm6000_core *dev, u8 mute)
738{
739 enum tm6000_inaudio ainp;
740
741 if (dev->radio)
742 ainp = dev->aradio;
743 else
744 ainp = dev->avideo;
745
746 switch (ainp) {
747 case TM6000_AIP_SIF1:
748 case TM6000_AIP_SIF2:
749 if (dev->dev_type == TM6010)
750 tm6010_set_mute_sif(dev, mute);
751 else {
752 printk(KERN_INFO "ERROR: TM5600 and TM6000 don't has"
753 " SIF audio inputs. Please check the %s"
754 " configuration.\n", dev->name);
755 return -EINVAL;
756 }
624 break; 757 break;
625 case 48000: 758 case TM6000_AIP_LINE1:
626 val |= 0x60; 759 case TM6000_AIP_LINE2:
627 dev->audio_bitrate = bitrate; 760 tm6010_set_mute_adc(dev, mute);
761 break;
762 default:
763 return -EINVAL;
628 break; 764 break;
629 } 765 }
630 if (dev->dev_type == TM6010) 766 return 0;
631 val = tm6000_set_reg(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 767}
632 val); 768EXPORT_SYMBOL_GPL(tm6000_tvaudio_set_mute);
633 else 769
634 val = tm6000_set_reg(dev, TM6000_REQ07_REB_VADC_AADC_MODE, val); 770void tm6010_set_volume_sif(struct tm6000_core *dev, int vol)
771{
772 u8 vol_reg;
635 773
636 return val; 774 vol_reg = vol & 0x0F;
775
776 if (vol < 0)
777 vol_reg |= 0x40;
778
779 tm6000_set_reg(dev, TM6010_REQ08_R07_A_LEFT_VOL, vol_reg);
780 tm6000_set_reg(dev, TM6010_REQ08_R08_A_RIGHT_VOL, vol_reg);
637} 781}
638EXPORT_SYMBOL_GPL(tm6000_set_audio_bitrate); 782
783void tm6010_set_volume_adc(struct tm6000_core *dev, int vol)
784{
785 u8 vol_reg;
786
787 vol_reg = (vol + 0x10) & 0x1f;
788
789 if (dev->dev_type == TM6010) {
790 tm6000_set_reg(dev, TM6010_REQ08_RF2_LEFT_CHANNEL_VOL, vol_reg);
791 tm6000_set_reg(dev, TM6010_REQ08_RF3_RIGHT_CHANNEL_VOL, vol_reg);
792 } else {
793 tm6000_set_reg(dev, TM6000_REQ07_REC_VADC_AADC_LVOL, vol_reg);
794 tm6000_set_reg(dev, TM6000_REQ07_RED_VADC_AADC_RVOL, vol_reg);
795 }
796}
797
798void tm6000_set_volume(struct tm6000_core *dev, int vol)
799{
800 enum tm6000_inaudio ainp;
801
802 if (dev->radio) {
803 ainp = dev->aradio;
804 vol += 8; /* Offset to 0 dB */
805 } else
806 ainp = dev->avideo;
807
808 switch (ainp) {
809 case TM6000_AIP_SIF1:
810 case TM6000_AIP_SIF2:
811 if (dev->dev_type == TM6010)
812 tm6010_set_volume_sif(dev, vol);
813 else
814 printk(KERN_INFO "ERROR: TM5600 and TM6000 don't has"
815 " SIF audio inputs. Please check the %s"
816 " configuration.\n", dev->name);
817 break;
818 case TM6000_AIP_LINE1:
819 case TM6000_AIP_LINE2:
820 tm6010_set_volume_adc(dev, vol);
821 break;
822 default:
823 break;
824 }
825}
826EXPORT_SYMBOL_GPL(tm6000_set_volume);
639 827
640static LIST_HEAD(tm6000_devlist); 828static LIST_HEAD(tm6000_devlist);
641static DEFINE_MUTEX(tm6000_devlist_mutex); 829static DEFINE_MUTEX(tm6000_devlist_mutex);
diff --git a/drivers/staging/tm6000/tm6000-stds.c b/drivers/staging/tm6000/tm6000-stds.c
index cc7b8664fc20..a4c07e5a6f1d 100644
--- a/drivers/staging/tm6000/tm6000-stds.c
+++ b/drivers/staging/tm6000/tm6000-stds.c
@@ -952,6 +952,22 @@ static int tm6000_set_audio_std(struct tm6000_core *dev,
952 uint8_t mono_flag = 0; /* No mono */ 952 uint8_t mono_flag = 0; /* No mono */
953 uint8_t nicam_flag = 0; /* No NICAM */ 953 uint8_t nicam_flag = 0; /* No NICAM */
954 954
955 if (dev->radio) {
956 tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x00);
957 tm6000_set_reg(dev, TM6010_REQ08_R02_A_FIX_GAIN_CTRL, 0x04);
958 tm6000_set_reg(dev, TM6010_REQ08_R03_A_AUTO_GAIN_CTRL, 0x00);
959 tm6000_set_reg(dev, TM6010_REQ08_R04_A_SIF_AMP_CTRL, 0x80);
960 tm6000_set_reg(dev, TM6010_REQ08_R05_A_STANDARD_MOD, 0x0c);
961 tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x00);
962 tm6000_set_reg(dev, TM6010_REQ08_R09_A_MAIN_VOL, 0x18);
963 tm6000_set_reg(dev, TM6010_REQ08_R0C_A_ASD_THRES2, 0x0a);
964 tm6000_set_reg(dev, TM6010_REQ08_R0D_A_AMD_THRES, 0x40);
965 tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc);
966 tm6000_set_reg(dev, TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT, 0x13);
967 tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x80);
968 return 0;
969 }
970
955 switch (std) { 971 switch (std) {
956#if 0 972#if 0
957 case DK_MONO: 973 case DK_MONO:
@@ -984,20 +1000,6 @@ static int tm6000_set_audio_std(struct tm6000_core *dev,
984 case EIAJ: 1000 case EIAJ:
985 areg_05 = 0x02; 1001 areg_05 = 0x02;
986 break; 1002 break;
987 case FM_RADIO:
988 tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x00);
989 tm6000_set_reg(dev, TM6010_REQ08_R02_A_FIX_GAIN_CTRL, 0x04);
990 tm6000_set_reg(dev, TM6010_REQ08_R03_A_AUTO_GAIN_CTRL, 0x00);
991 tm6000_set_reg(dev, TM6010_REQ08_R05_A_STANDARD_MOD, 0x0c);
992 tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x00);
993 tm6000_set_reg(dev, TM6010_REQ08_R09_A_MAIN_VOL, 0x18);
994 tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, 0x91);
995 tm6000_set_reg(dev, TM6010_REQ08_R16_A_AGC_GAIN_MAX, 0xfe);
996 tm6000_set_reg(dev, TM6010_REQ08_R17_A_AGC_GAIN_MIN, 0x01);
997 tm6000_set_reg(dev, TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT, 0x13);
998 tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x80);
999 return 0;
1000 break;
1001 case I_NICAM: 1003 case I_NICAM:
1002 areg_05 = 0x08; 1004 areg_05 = 0x08;
1003 nicam_flag = 1; 1005 nicam_flag = 1;
@@ -1010,6 +1012,9 @@ static int tm6000_set_audio_std(struct tm6000_core *dev,
1010 areg_05 = 0x0a; 1012 areg_05 = 0x0a;
1011 nicam_flag = 1; 1013 nicam_flag = 1;
1012 break; 1014 break;
1015 default:
1016 /* do nothink */
1017 break;
1013 } 1018 }
1014 1019
1015#if 0 1020#if 0
diff --git a/drivers/staging/tm6000/tm6000-video.c b/drivers/staging/tm6000/tm6000-video.c
index eb9b9f1bc138..b5503409ca55 100644
--- a/drivers/staging/tm6000/tm6000-video.c
+++ b/drivers/staging/tm6000/tm6000-video.c
@@ -53,11 +53,17 @@
53/* Declare static vars that will be used as parameters */ 53/* Declare static vars that will be used as parameters */
54static unsigned int vid_limit = 16; /* Video memory limit, in Mb */ 54static unsigned int vid_limit = 16; /* Video memory limit, in Mb */
55static int video_nr = -1; /* /dev/videoN, -1 for autodetect */ 55static int video_nr = -1; /* /dev/videoN, -1 for autodetect */
56static int radio_nr = -1; /* /dev/radioN, -1 for autodetect */
56 57
57/* Debug level */ 58/* Debug level */
58int tm6000_debug; 59int tm6000_debug;
59EXPORT_SYMBOL_GPL(tm6000_debug); 60EXPORT_SYMBOL_GPL(tm6000_debug);
60 61
62static const struct v4l2_queryctrl no_ctrl = {
63 .name = "42",
64 .flags = V4L2_CTRL_FLAG_DISABLED,
65};
66
61/* supported controls */ 67/* supported controls */
62static struct v4l2_queryctrl tm6000_qctrl[] = { 68static struct v4l2_queryctrl tm6000_qctrl[] = {
63 { 69 {
@@ -96,9 +102,26 @@ static struct v4l2_queryctrl tm6000_qctrl[] = {
96 .step = 0x1, 102 .step = 0x1,
97 .default_value = 0, 103 .default_value = 0,
98 .flags = 0, 104 .flags = 0,
105 },
106 /* --- audio --- */
107 {
108 .id = V4L2_CID_AUDIO_MUTE,
109 .name = "Mute",
110 .minimum = 0,
111 .maximum = 1,
112 .type = V4L2_CTRL_TYPE_BOOLEAN,
113 }, {
114 .id = V4L2_CID_AUDIO_VOLUME,
115 .name = "Volume",
116 .minimum = -15,
117 .maximum = 15,
118 .step = 1,
119 .default_value = 0,
120 .type = V4L2_CTRL_TYPE_INTEGER,
99 } 121 }
100}; 122};
101 123
124static const unsigned int CTRLS = ARRAY_SIZE(tm6000_qctrl);
102static int qctl_regs[ARRAY_SIZE(tm6000_qctrl)]; 125static int qctl_regs[ARRAY_SIZE(tm6000_qctrl)];
103 126
104static struct tm6000_fmt format[] = { 127static struct tm6000_fmt format[] = {
@@ -117,6 +140,16 @@ static struct tm6000_fmt format[] = {
117 } 140 }
118}; 141};
119 142
143static const struct v4l2_queryctrl *ctrl_by_id(unsigned int id)
144{
145 unsigned int i;
146
147 for (i = 0; i < CTRLS; i++)
148 if (tm6000_qctrl[i].id == id)
149 return tm6000_qctrl+i;
150 return NULL;
151}
152
120/* ------------------------------------------------------------------ 153/* ------------------------------------------------------------------
121 * DMA and thread functions 154 * DMA and thread functions
122 * ------------------------------------------------------------------ 155 * ------------------------------------------------------------------
@@ -199,13 +232,17 @@ static int copy_streams(u8 *data, unsigned long len,
199 char *voutp = NULL; 232 char *voutp = NULL;
200 unsigned int linewidth; 233 unsigned int linewidth;
201 234
202 /* get video buffer */ 235 if (!dev->radio) {
203 get_next_buf(dma_q, &vbuf); 236 /* get video buffer */
204 if (!vbuf) 237 get_next_buf(dma_q, &vbuf);
205 return rc; 238
206 voutp = videobuf_to_vmalloc(&vbuf->vb); 239 if (!vbuf)
207 if (!voutp) 240 return rc;
208 return 0; 241 voutp = videobuf_to_vmalloc(&vbuf->vb);
242
243 if (!voutp)
244 return 0;
245 }
209 246
210 for (ptr = data; ptr < endp;) { 247 for (ptr = data; ptr < endp;) {
211 if (!dev->isoc_ctl.cmd) { 248 if (!dev->isoc_ctl.cmd) {
@@ -257,29 +294,31 @@ static int copy_streams(u8 *data, unsigned long len,
257 */ 294 */
258 switch (cmd) { 295 switch (cmd) {
259 case TM6000_URB_MSG_VIDEO: 296 case TM6000_URB_MSG_VIDEO:
260 if ((dev->isoc_ctl.vfield != field) && 297 if (!dev->radio) {
261 (field == 1)) { 298 if ((dev->isoc_ctl.vfield != field) &&
299 (field == 1)) {
262 /* Announces that a new buffer 300 /* Announces that a new buffer
263 * were filled 301 * were filled
264 */ 302 */
265 buffer_filled(dev, dma_q, vbuf); 303 buffer_filled(dev, dma_q, vbuf);
266 dprintk(dev, V4L2_DEBUG_ISOC, 304 dprintk(dev, V4L2_DEBUG_ISOC,
267 "new buffer filled\n"); 305 "new buffer filled\n");
268 get_next_buf(dma_q, &vbuf); 306 get_next_buf(dma_q, &vbuf);
269 if (!vbuf) 307 if (!vbuf)
270 return rc; 308 return rc;
271 voutp = videobuf_to_vmalloc(&vbuf->vb); 309 voutp = videobuf_to_vmalloc(&vbuf->vb);
272 if (!voutp) 310 if (!voutp)
273 return rc; 311 return rc;
274 memset(voutp, 0, vbuf->vb.size); 312 memset(voutp, 0, vbuf->vb.size);
275 } 313 }
276 linewidth = vbuf->vb.width << 1; 314 linewidth = vbuf->vb.width << 1;
277 pos = ((line << 1) - field - 1) * linewidth + 315 pos = ((line << 1) - field - 1) *
278 block * TM6000_URB_MSG_LEN; 316 linewidth + block * TM6000_URB_MSG_LEN;
279 /* Don't allow to write out of the buffer */ 317 /* Don't allow to write out of the buffer */
280 if (pos + size > vbuf->vb.size) 318 if (pos + size > vbuf->vb.size)
281 cmd = TM6000_URB_MSG_ERR; 319 cmd = TM6000_URB_MSG_ERR;
282 dev->isoc_ctl.vfield = field; 320 dev->isoc_ctl.vfield = field;
321 }
283 break; 322 break;
284 case TM6000_URB_MSG_VBI: 323 case TM6000_URB_MSG_VBI:
285 break; 324 break;
@@ -537,7 +576,7 @@ static void tm6000_uninit_isoc(struct tm6000_core *dev)
537/* 576/*
538 * Allocate URBs and start IRQ 577 * Allocate URBs and start IRQ
539 */ 578 */
540static int tm6000_prepare_isoc(struct tm6000_core *dev, unsigned int framesize) 579static int tm6000_prepare_isoc(struct tm6000_core *dev)
541{ 580{
542 struct tm6000_dmaqueue *dma_q = &dev->vidq; 581 struct tm6000_dmaqueue *dma_q = &dev->vidq;
543 int i, j, sb_size, pipe, size, max_packets, num_bufs = 8; 582 int i, j, sb_size, pipe, size, max_packets, num_bufs = 8;
@@ -566,11 +605,7 @@ static int tm6000_prepare_isoc(struct tm6000_core *dev, unsigned int framesize)
566 605
567 dev->isoc_ctl.max_pkt_size = size; 606 dev->isoc_ctl.max_pkt_size = size;
568 607
569 max_packets = (framesize + size - 1) / size; 608 max_packets = TM6000_MAX_ISO_PACKETS;
570
571 if (max_packets > TM6000_MAX_ISO_PACKETS)
572 max_packets = TM6000_MAX_ISO_PACKETS;
573
574 sb_size = max_packets * size; 609 sb_size = max_packets * size;
575 610
576 dev->isoc_ctl.num_bufs = num_bufs; 611 dev->isoc_ctl.num_bufs = num_bufs;
@@ -746,7 +781,7 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
746 urb_init = 1; 781 urb_init = 1;
747 782
748 if (urb_init) { 783 if (urb_init) {
749 rc = tm6000_prepare_isoc(dev, buf->vb.size); 784 rc = tm6000_prepare_isoc(dev);
750 if (rc < 0) 785 if (rc < 0)
751 goto fail; 786 goto fail;
752 787
@@ -1143,6 +1178,12 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
1143 case V4L2_CID_HUE: 1178 case V4L2_CID_HUE:
1144 val = tm6000_get_reg(dev, TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ, 0); 1179 val = tm6000_get_reg(dev, TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ, 0);
1145 return 0; 1180 return 0;
1181 case V4L2_CID_AUDIO_MUTE:
1182 val = dev->ctl_mute;
1183 return 0;
1184 case V4L2_CID_AUDIO_VOLUME:
1185 val = dev->ctl_volume;
1186 return 0;
1146 default: 1187 default:
1147 return -EINVAL; 1188 return -EINVAL;
1148 } 1189 }
@@ -1174,6 +1215,14 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
1174 case V4L2_CID_HUE: 1215 case V4L2_CID_HUE:
1175 tm6000_set_reg(dev, TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ, val); 1216 tm6000_set_reg(dev, TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ, val);
1176 return 0; 1217 return 0;
1218 case V4L2_CID_AUDIO_MUTE:
1219 dev->ctl_mute = val;
1220 tm6000_tvaudio_set_mute(dev, val);
1221 return 0;
1222 case V4L2_CID_AUDIO_VOLUME:
1223 dev->ctl_volume = val;
1224 tm6000_set_volume(dev, val);
1225 return 0;
1177 } 1226 }
1178 return -EINVAL; 1227 return -EINVAL;
1179} 1228}
@@ -1221,7 +1270,7 @@ static int vidioc_g_frequency(struct file *file, void *priv,
1221 if (unlikely(UNSET == dev->tuner_type)) 1270 if (unlikely(UNSET == dev->tuner_type))
1222 return -EINVAL; 1271 return -EINVAL;
1223 1272
1224 f->type = V4L2_TUNER_ANALOG_TV; 1273 f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
1225 f->frequency = dev->freq; 1274 f->frequency = dev->freq;
1226 1275
1227 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, f); 1276 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, f);
@@ -1235,13 +1284,14 @@ static int vidioc_s_frequency(struct file *file, void *priv,
1235 struct tm6000_fh *fh = priv; 1284 struct tm6000_fh *fh = priv;
1236 struct tm6000_core *dev = fh->dev; 1285 struct tm6000_core *dev = fh->dev;
1237 1286
1238 if (unlikely(f->type != V4L2_TUNER_ANALOG_TV))
1239 return -EINVAL;
1240
1241 if (unlikely(UNSET == dev->tuner_type)) 1287 if (unlikely(UNSET == dev->tuner_type))
1242 return -EINVAL; 1288 return -EINVAL;
1243 if (unlikely(f->tuner != 0)) 1289 if (unlikely(f->tuner != 0))
1244 return -EINVAL; 1290 return -EINVAL;
1291 if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type)
1292 return -EINVAL;
1293 if (1 == fh->radio && V4L2_TUNER_RADIO != f->type)
1294 return -EINVAL;
1245 1295
1246 dev->freq = f->frequency; 1296 dev->freq = f->frequency;
1247 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, f); 1297 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, f);
@@ -1249,6 +1299,122 @@ static int vidioc_s_frequency(struct file *file, void *priv,
1249 return 0; 1299 return 0;
1250} 1300}
1251 1301
1302static int radio_querycap(struct file *file, void *priv,
1303 struct v4l2_capability *cap)
1304{
1305 struct tm6000_fh *fh = file->private_data;
1306 struct tm6000_core *dev = fh->dev;
1307
1308 strcpy(cap->driver, "tm6000");
1309 strlcpy(cap->card, dev->name, sizeof(dev->name));
1310 sprintf(cap->bus_info, "USB%04x:%04x",
1311 le16_to_cpu(dev->udev->descriptor.idVendor),
1312 le16_to_cpu(dev->udev->descriptor.idProduct));
1313 cap->version = dev->dev_type;
1314 cap->capabilities = V4L2_CAP_TUNER;
1315
1316 return 0;
1317}
1318
1319static int radio_g_tuner(struct file *file, void *priv,
1320 struct v4l2_tuner *t)
1321{
1322 struct tm6000_fh *fh = file->private_data;
1323 struct tm6000_core *dev = fh->dev;
1324
1325 if (0 != t->index)
1326 return -EINVAL;
1327
1328 memset(t, 0, sizeof(*t));
1329 strcpy(t->name, "Radio");
1330 t->type = V4L2_TUNER_RADIO;
1331
1332 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
1333
1334 if ((dev->aradio == TM6000_AIP_LINE1) ||
1335 (dev->aradio == TM6000_AIP_LINE2)) {
1336 t->rxsubchans = V4L2_TUNER_SUB_MONO;
1337 }
1338 else {
1339 t->rxsubchans = V4L2_TUNER_SUB_STEREO;
1340 }
1341
1342 return 0;
1343}
1344
1345static int radio_s_tuner(struct file *file, void *priv,
1346 struct v4l2_tuner *t)
1347{
1348 struct tm6000_fh *fh = file->private_data;
1349 struct tm6000_core *dev = fh->dev;
1350
1351 if (0 != t->index)
1352 return -EINVAL;
1353
1354 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
1355
1356 return 0;
1357}
1358
1359static int radio_enum_input(struct file *file, void *priv,
1360 struct v4l2_input *i)
1361{
1362 if (i->index != 0)
1363 return -EINVAL;
1364
1365 strcpy(i->name, "Radio");
1366 i->type = V4L2_INPUT_TYPE_TUNER;
1367
1368 return 0;
1369}
1370
1371static int radio_g_input(struct file *filp, void *priv, unsigned int *i)
1372{
1373 *i = 0;
1374 return 0;
1375}
1376
1377static int radio_g_audio(struct file *file, void *priv,
1378 struct v4l2_audio *a)
1379{
1380 memset(a, 0, sizeof(*a));
1381 strcpy(a->name, "Radio");
1382 return 0;
1383}
1384
1385static int radio_s_audio(struct file *file, void *priv,
1386 struct v4l2_audio *a)
1387{
1388 return 0;
1389}
1390
1391static int radio_s_input(struct file *filp, void *priv, unsigned int i)
1392{
1393 return 0;
1394}
1395
1396static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm)
1397{
1398 return 0;
1399}
1400
1401static int radio_queryctrl(struct file *file, void *priv,
1402 struct v4l2_queryctrl *c)
1403{
1404 const struct v4l2_queryctrl *ctrl;
1405
1406 if (c->id < V4L2_CID_BASE ||
1407 c->id >= V4L2_CID_LASTP1)
1408 return -EINVAL;
1409 if (c->id == V4L2_CID_AUDIO_MUTE) {
1410 ctrl = ctrl_by_id(c->id);
1411 *c = *ctrl;
1412 } else
1413 *c = no_ctrl;
1414
1415 return 0;
1416}
1417
1252/* ------------------------------------------------------------------ 1418/* ------------------------------------------------------------------
1253 File operations for the device 1419 File operations for the device
1254 ------------------------------------------------------------------*/ 1420 ------------------------------------------------------------------*/
@@ -1260,6 +1426,7 @@ static int tm6000_open(struct file *file)
1260 struct tm6000_fh *fh; 1426 struct tm6000_fh *fh;
1261 enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 1427 enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1262 int i, rc; 1428 int i, rc;
1429 int radio = 0;
1263 1430
1264 printk(KERN_INFO "tm6000: open called (dev=%s)\n", 1431 printk(KERN_INFO "tm6000: open called (dev=%s)\n",
1265 video_device_node_name(vdev)); 1432 video_device_node_name(vdev));
@@ -1267,6 +1434,17 @@ static int tm6000_open(struct file *file)
1267 dprintk(dev, V4L2_DEBUG_OPEN, "tm6000: open called (dev=%s)\n", 1434 dprintk(dev, V4L2_DEBUG_OPEN, "tm6000: open called (dev=%s)\n",
1268 video_device_node_name(vdev)); 1435 video_device_node_name(vdev));
1269 1436
1437 switch (vdev->vfl_type) {
1438 case VFL_TYPE_GRABBER:
1439 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1440 break;
1441 case VFL_TYPE_VBI:
1442 type = V4L2_BUF_TYPE_VBI_CAPTURE;
1443 break;
1444 case VFL_TYPE_RADIO:
1445 radio = 1;
1446 break;
1447 }
1270 1448
1271 /* If more than one user, mutex should be added */ 1449 /* If more than one user, mutex should be added */
1272 dev->users++; 1450 dev->users++;
@@ -1284,8 +1462,9 @@ static int tm6000_open(struct file *file)
1284 1462
1285 file->private_data = fh; 1463 file->private_data = fh;
1286 fh->dev = dev; 1464 fh->dev = dev;
1287 1465 fh->radio = radio;
1288 fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 1466 dev->radio = radio;
1467 fh->type = type;
1289 dev->fourcc = format[0].fourcc; 1468 dev->fourcc = format[0].fourcc;
1290 1469
1291 fh->fmt = format_by_fourcc(dev->fourcc); 1470 fh->fmt = format_by_fourcc(dev->fourcc);
@@ -1322,6 +1501,19 @@ static int tm6000_open(struct file *file)
1322 V4L2_FIELD_INTERLACED, 1501 V4L2_FIELD_INTERLACED,
1323 sizeof(struct tm6000_buffer), fh, &dev->lock); 1502 sizeof(struct tm6000_buffer), fh, &dev->lock);
1324 1503
1504 if (fh->radio) {
1505 dprintk(dev, V4L2_DEBUG_OPEN, "video_open: setting radio device\n");
1506 tm6000_set_audio_input(dev, dev->aradio);
1507 tm6000_set_volume(dev, dev->ctl_volume);
1508 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_radio);
1509 tm6000_prepare_isoc(dev);
1510 tm6000_start_thread(dev);
1511 }
1512 else {
1513 tm6000_set_audio_input(dev, dev->avideo);
1514 tm6000_set_volume(dev, dev->ctl_volume);
1515 }
1516
1325 return 0; 1517 return 0;
1326} 1518}
1327 1519
@@ -1445,6 +1637,36 @@ static struct video_device tm6000_template = {
1445 .current_norm = V4L2_STD_NTSC_M, 1637 .current_norm = V4L2_STD_NTSC_M,
1446}; 1638};
1447 1639
1640static const struct v4l2_file_operations radio_fops = {
1641 .owner = THIS_MODULE,
1642 .open = tm6000_open,
1643 .release = tm6000_release,
1644 .ioctl = video_ioctl2,
1645};
1646
1647static const struct v4l2_ioctl_ops radio_ioctl_ops = {
1648 .vidioc_querycap = radio_querycap,
1649 .vidioc_g_tuner = radio_g_tuner,
1650 .vidioc_enum_input = radio_enum_input,
1651 .vidioc_g_audio = radio_g_audio,
1652 .vidioc_s_tuner = radio_s_tuner,
1653 .vidioc_s_audio = radio_s_audio,
1654 .vidioc_s_input = radio_s_input,
1655 .vidioc_s_std = radio_s_std,
1656 .vidioc_queryctrl = radio_queryctrl,
1657 .vidioc_g_input = radio_g_input,
1658 .vidioc_g_ctrl = vidioc_g_ctrl,
1659 .vidioc_s_ctrl = vidioc_s_ctrl,
1660 .vidioc_g_frequency = vidioc_g_frequency,
1661 .vidioc_s_frequency = vidioc_s_frequency,
1662};
1663
1664struct video_device tm6000_radio_template = {
1665 .name = "tm6000",
1666 .fops = &radio_fops,
1667 .ioctl_ops = &radio_ioctl_ops,
1668};
1669
1448/* ----------------------------------------------------------------- 1670/* -----------------------------------------------------------------
1449 * Initialization and module stuff 1671 * Initialization and module stuff
1450 * ------------------------------------------------------------------ 1672 * ------------------------------------------------------------------
@@ -1499,6 +1721,25 @@ int tm6000_v4l2_register(struct tm6000_core *dev)
1499 printk(KERN_INFO "%s: registered device %s\n", 1721 printk(KERN_INFO "%s: registered device %s\n",
1500 dev->name, video_device_node_name(dev->vfd)); 1722 dev->name, video_device_node_name(dev->vfd));
1501 1723
1724 dev->radio_dev = vdev_init(dev, &tm6000_radio_template,
1725 "radio");
1726 if (!dev->radio_dev) {
1727 printk(KERN_INFO "%s: can't register radio device\n",
1728 dev->name);
1729 return ret; /* FIXME release resource */
1730 }
1731
1732 ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
1733 radio_nr);
1734 if (ret < 0) {
1735 printk(KERN_INFO "%s: can't register radio device\n",
1736 dev->name);
1737 return ret; /* FIXME release resource */
1738 }
1739
1740 printk(KERN_INFO "%s: registered device %s\n",
1741 dev->name, video_device_node_name(dev->radio_dev));
1742
1502 printk(KERN_INFO "Trident TVMaster TM5600/TM6000/TM6010 USB2 board (Load status: %d)\n", ret); 1743 printk(KERN_INFO "Trident TVMaster TM5600/TM6000/TM6010 USB2 board (Load status: %d)\n", ret);
1503 return ret; 1744 return ret;
1504} 1745}
@@ -1507,6 +1748,14 @@ int tm6000_v4l2_unregister(struct tm6000_core *dev)
1507{ 1748{
1508 video_unregister_device(dev->vfd); 1749 video_unregister_device(dev->vfd);
1509 1750
1751 if (dev->radio_dev) {
1752 if (video_is_registered(dev->radio_dev))
1753 video_unregister_device(dev->radio_dev);
1754 else
1755 video_device_release(dev->radio_dev);
1756 dev->radio_dev = NULL;
1757 }
1758
1510 return 0; 1759 return 0;
1511} 1760}
1512 1761
diff --git a/drivers/staging/tm6000/tm6000.h b/drivers/staging/tm6000/tm6000.h
index bf11eeec92c7..ccd120fe1340 100644
--- a/drivers/staging/tm6000/tm6000.h
+++ b/drivers/staging/tm6000/tm6000.h
@@ -53,6 +53,14 @@ enum tm6000_devtype {
53 TM6010, 53 TM6010,
54}; 54};
55 55
56enum tm6000_inaudio {
57 TM6000_AIP_UNK = 0,
58 TM6000_AIP_SIF1,
59 TM6000_AIP_SIF2,
60 TM6000_AIP_LINE1,
61 TM6000_AIP_LINE2,
62};
63
56/* ------------------------------------------------------------------ 64/* ------------------------------------------------------------------
57 * Basic structures 65 * Basic structures
58 * ------------------------------------------------------------------ 66 * ------------------------------------------------------------------
@@ -174,6 +182,8 @@ struct tm6000_core {
174 182
175 char *ir_codes; 183 char *ir_codes;
176 184
185 __u8 radio;
186
177 /* Demodulator configuration */ 187 /* Demodulator configuration */
178 int demod_addr; /* demodulator address */ 188 int demod_addr; /* demodulator address */
179 189
@@ -194,6 +204,7 @@ struct tm6000_core {
194 bool is_res_read; 204 bool is_res_read;
195 205
196 struct video_device *vfd; 206 struct video_device *vfd;
207 struct video_device *radio_dev;
197 struct tm6000_dmaqueue vidq; 208 struct tm6000_dmaqueue vidq;
198 struct v4l2_device v4l2_dev; 209 struct v4l2_device v4l2_dev;
199 210
@@ -203,6 +214,9 @@ struct tm6000_core {
203 214
204 enum tm6000_mode mode; 215 enum tm6000_mode mode;
205 216
217 int ctl_mute; /* audio */
218 int ctl_volume;
219
206 /* DVB-T support */ 220 /* DVB-T support */
207 struct tm6000_dvb *dvb; 221 struct tm6000_dvb *dvb;
208 222
@@ -210,7 +224,8 @@ struct tm6000_core {
210 struct snd_tm6000_card *adev; 224 struct snd_tm6000_card *adev;
211 struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */ 225 struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */
212 atomic_t stream_started; /* stream should be running if true */ 226 atomic_t stream_started; /* stream should be running if true */
213 227 enum tm6000_inaudio avideo;
228 enum tm6000_inaudio aradio;
214 229
215 struct tm6000_IR *ir; 230 struct tm6000_IR *ir;
216 231
@@ -248,6 +263,7 @@ struct tm6000_ops {
248 263
249struct tm6000_fh { 264struct tm6000_fh {
250 struct tm6000_core *dev; 265 struct tm6000_core *dev;
266 unsigned int radio;
251 267
252 /* video capture */ 268 /* video capture */
253 struct tm6000_fmt *fmt; 269 struct tm6000_fmt *fmt;
@@ -276,12 +292,17 @@ int tm6000_get_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index);
276int tm6000_get_reg16(struct tm6000_core *dev, u8 req, u16 value, u16 index); 292int tm6000_get_reg16(struct tm6000_core *dev, u8 req, u16 value, u16 index);
277int tm6000_get_reg32(struct tm6000_core *dev, u8 req, u16 value, u16 index); 293int tm6000_get_reg32(struct tm6000_core *dev, u8 req, u16 value, u16 index);
278int tm6000_set_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index); 294int tm6000_set_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index);
295int tm6000_set_reg_mask(struct tm6000_core *dev, u8 req, u16 value,
296 u16 index, u16 mask);
279int tm6000_i2c_reset(struct tm6000_core *dev, u16 tsleep); 297int tm6000_i2c_reset(struct tm6000_core *dev, u16 tsleep);
280int tm6000_init(struct tm6000_core *dev); 298int tm6000_init(struct tm6000_core *dev);
281 299
282int tm6000_init_analog_mode(struct tm6000_core *dev); 300int tm6000_init_analog_mode(struct tm6000_core *dev);
283int tm6000_init_digital_mode(struct tm6000_core *dev); 301int tm6000_init_digital_mode(struct tm6000_core *dev);
284int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate); 302int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate);
303int tm6000_set_audio_input(struct tm6000_core *dev, enum tm6000_inaudio ainp);
304int tm6000_tvaudio_set_mute(struct tm6000_core *dev, u8 mute);
305void tm6000_set_volume(struct tm6000_core *dev, int vol);
285 306
286int tm6000_v4l2_register(struct tm6000_core *dev); 307int tm6000_v4l2_register(struct tm6000_core *dev);
287int tm6000_v4l2_unregister(struct tm6000_core *dev); 308int tm6000_v4l2_unregister(struct tm6000_core *dev);