aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/cx88
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/cx88')
-rw-r--r--drivers/media/video/cx88/cx88-alsa.c10
-rw-r--r--drivers/media/video/cx88/cx88-cards.c23
-rw-r--r--drivers/media/video/cx88/cx88-dvb.c214
-rw-r--r--drivers/media/video/cx88/cx88-input.c4
-rw-r--r--drivers/media/video/cx88/cx88-mpeg.c3
-rw-r--r--drivers/media/video/cx88/cx88.h1
6 files changed, 249 insertions, 6 deletions
diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
index 5a67445dd6ed..64b350df78e3 100644
--- a/drivers/media/video/cx88/cx88-alsa.c
+++ b/drivers/media/video/cx88/cx88-alsa.c
@@ -583,16 +583,18 @@ static int snd_cx88_volume_put(struct snd_kcontrol *kcontrol,
583{ 583{
584 snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); 584 snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
585 struct cx88_core *core=chip->core; 585 struct cx88_core *core=chip->core;
586 int v, b; 586 int left, right, v, b;
587 int changed = 0; 587 int changed = 0;
588 u32 old; 588 u32 old;
589 589
590 b = value->value.integer.value[1] - value->value.integer.value[0]; 590 left = value->value.integer.value[0] & 0x3f;
591 right = value->value.integer.value[1] & 0x3f;
592 b = right - left;
591 if (b < 0) { 593 if (b < 0) {
592 v = 0x3f - value->value.integer.value[0]; 594 v = 0x3f - left;
593 b = (-b) | 0x40; 595 b = (-b) | 0x40;
594 } else { 596 } else {
595 v = 0x3f - value->value.integer.value[1]; 597 v = 0x3f - right;
596 } 598 }
597 /* Do we really know this will always be called with IRQs on? */ 599 /* Do we really know this will always be called with IRQs on? */
598 spin_lock_irq(&chip->reg_lock); 600 spin_lock_irq(&chip->reg_lock);
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index d844f2aaa01d..eaf0ee7de832 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -1466,6 +1466,18 @@ static const struct cx88_board cx88_boards[] = {
1466 .audioroute = 8, 1466 .audioroute = 8,
1467 }, 1467 },
1468 }, 1468 },
1469 [CX88_BOARD_SAMSUNG_SMT_7020] = {
1470 .name = "Samsung SMT 7020 DVB-S",
1471 .tuner_type = TUNER_ABSENT,
1472 .radio_type = UNSET,
1473 .tuner_addr = ADDR_UNSET,
1474 .radio_addr = ADDR_UNSET,
1475 .input = { {
1476 .type = CX88_VMUX_DVB,
1477 .vmux = 0,
1478 } },
1479 .mpeg = CX88_MPEG_DVB,
1480 },
1469 [CX88_BOARD_ADSTECH_PTV_390] = { 1481 [CX88_BOARD_ADSTECH_PTV_390] = {
1470 .name = "ADS Tech Instant Video PCI", 1482 .name = "ADS Tech Instant Video PCI",
1471 .tuner_type = TUNER_ABSENT, 1483 .tuner_type = TUNER_ABSENT,
@@ -2355,6 +2367,14 @@ static const struct cx88_subid cx88_subids[] = {
2355 .subvendor = 0x0070, 2367 .subvendor = 0x0070,
2356 .subdevice = 0x1404, 2368 .subdevice = 0x1404,
2357 .card = CX88_BOARD_HAUPPAUGE_HVR3000, 2369 .card = CX88_BOARD_HAUPPAUGE_HVR3000,
2370 }, {
2371 .subvendor = 0x18ac,
2372 .subdevice = 0xdc00,
2373 .card = CX88_BOARD_SAMSUNG_SMT_7020,
2374 }, {
2375 .subvendor = 0x18ac,
2376 .subdevice = 0xdccd,
2377 .card = CX88_BOARD_SAMSUNG_SMT_7020,
2358 },{ 2378 },{
2359 .subvendor = 0x1461, 2379 .subvendor = 0x1461,
2360 .subdevice = 0xc111, /* AverMedia M150-D */ 2380 .subdevice = 0xc111, /* AverMedia M150-D */
@@ -2633,6 +2653,9 @@ static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data)
2633 case 98559: /* WinTV-HVR1100LP (Video no IR, Retail - Low Profile) */ 2653 case 98559: /* WinTV-HVR1100LP (Video no IR, Retail - Low Profile) */
2634 /* known */ 2654 /* known */
2635 break; 2655 break;
2656 case CX88_BOARD_SAMSUNG_SMT_7020:
2657 cx_set(MO_GP0_IO, 0x008989FF);
2658 break;
2636 default: 2659 default:
2637 warn_printk(core, "warning: unknown hauppauge model #%d\n", 2660 warn_printk(core, "warning: unknown hauppauge model #%d\n",
2638 tv.model); 2661 tv.model);
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index b14296923250..94ab862f0219 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -674,6 +674,194 @@ static int cx8802_alloc_frontends(struct cx8802_dev *dev)
674 return 0; 674 return 0;
675} 675}
676 676
677
678
679static u8 samsung_smt_7020_inittab[] = {
680 0x01, 0x15,
681 0x02, 0x00,
682 0x03, 0x00,
683 0x04, 0x7D,
684 0x05, 0x0F,
685 0x06, 0x02,
686 0x07, 0x00,
687 0x08, 0x60,
688
689 0x0A, 0xC2,
690 0x0B, 0x00,
691 0x0C, 0x01,
692 0x0D, 0x81,
693 0x0E, 0x44,
694 0x0F, 0x09,
695 0x10, 0x3C,
696 0x11, 0x84,
697 0x12, 0xDA,
698 0x13, 0x99,
699 0x14, 0x8D,
700 0x15, 0xCE,
701 0x16, 0xE8,
702 0x17, 0x43,
703 0x18, 0x1C,
704 0x19, 0x1B,
705 0x1A, 0x1D,
706
707 0x1C, 0x12,
708 0x1D, 0x00,
709 0x1E, 0x00,
710 0x1F, 0x00,
711 0x20, 0x00,
712 0x21, 0x00,
713 0x22, 0x00,
714 0x23, 0x00,
715
716 0x28, 0x02,
717 0x29, 0x28,
718 0x2A, 0x14,
719 0x2B, 0x0F,
720 0x2C, 0x09,
721 0x2D, 0x05,
722
723 0x31, 0x1F,
724 0x32, 0x19,
725 0x33, 0xFC,
726 0x34, 0x13,
727 0xff, 0xff,
728};
729
730
731static int samsung_smt_7020_tuner_set_params(struct dvb_frontend *fe,
732 struct dvb_frontend_parameters *params)
733{
734 struct cx8802_dev *dev = fe->dvb->priv;
735 u8 buf[4];
736 u32 div;
737 struct i2c_msg msg = {
738 .addr = 0x61,
739 .flags = 0,
740 .buf = buf,
741 .len = sizeof(buf) };
742
743 div = params->frequency / 125;
744
745 buf[0] = (div >> 8) & 0x7f;
746 buf[1] = div & 0xff;
747 buf[2] = 0x84; /* 0xC4 */
748 buf[3] = 0x00;
749
750 if (params->frequency < 1500000)
751 buf[3] |= 0x10;
752
753 if (fe->ops.i2c_gate_ctrl)
754 fe->ops.i2c_gate_ctrl(fe, 1);
755
756 if (i2c_transfer(&dev->core->i2c_adap, &msg, 1) != 1)
757 return -EIO;
758
759 return 0;
760}
761
762static int samsung_smt_7020_set_tone(struct dvb_frontend *fe,
763 fe_sec_tone_mode_t tone)
764{
765 struct cx8802_dev *dev = fe->dvb->priv;
766 struct cx88_core *core = dev->core;
767
768 cx_set(MO_GP0_IO, 0x0800);
769
770 switch (tone) {
771 case SEC_TONE_ON:
772 cx_set(MO_GP0_IO, 0x08);
773 break;
774 case SEC_TONE_OFF:
775 cx_clear(MO_GP0_IO, 0x08);
776 break;
777 default:
778 return -EINVAL;
779 }
780
781 return 0;
782}
783
784static int samsung_smt_7020_set_voltage(struct dvb_frontend *fe,
785 fe_sec_voltage_t voltage)
786{
787 struct cx8802_dev *dev = fe->dvb->priv;
788 struct cx88_core *core = dev->core;
789
790 u8 data;
791 struct i2c_msg msg = {
792 .addr = 8,
793 .flags = 0,
794 .buf = &data,
795 .len = sizeof(data) };
796
797 cx_set(MO_GP0_IO, 0x8000);
798
799 switch (voltage) {
800 case SEC_VOLTAGE_OFF:
801 break;
802 case SEC_VOLTAGE_13:
803 data = ISL6421_EN1 | ISL6421_LLC1;
804 cx_clear(MO_GP0_IO, 0x80);
805 break;
806 case SEC_VOLTAGE_18:
807 data = ISL6421_EN1 | ISL6421_LLC1 | ISL6421_VSEL1;
808 cx_clear(MO_GP0_IO, 0x80);
809 break;
810 default:
811 return -EINVAL;
812 };
813
814 return (i2c_transfer(&dev->core->i2c_adap, &msg, 1) == 1) ? 0 : -EIO;
815}
816
817static int samsung_smt_7020_stv0299_set_symbol_rate(struct dvb_frontend *fe,
818 u32 srate, u32 ratio)
819{
820 u8 aclk = 0;
821 u8 bclk = 0;
822
823 if (srate < 1500000) {
824 aclk = 0xb7;
825 bclk = 0x47;
826 } else if (srate < 3000000) {
827 aclk = 0xb7;
828 bclk = 0x4b;
829 } else if (srate < 7000000) {
830 aclk = 0xb7;
831 bclk = 0x4f;
832 } else if (srate < 14000000) {
833 aclk = 0xb7;
834 bclk = 0x53;
835 } else if (srate < 30000000) {
836 aclk = 0xb6;
837 bclk = 0x53;
838 } else if (srate < 45000000) {
839 aclk = 0xb4;
840 bclk = 0x51;
841 }
842
843 stv0299_writereg(fe, 0x13, aclk);
844 stv0299_writereg(fe, 0x14, bclk);
845 stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
846 stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
847 stv0299_writereg(fe, 0x21, ratio & 0xf0);
848
849 return 0;
850}
851
852
853static struct stv0299_config samsung_stv0299_config = {
854 .demod_address = 0x68,
855 .inittab = samsung_smt_7020_inittab,
856 .mclk = 88000000UL,
857 .invert = 0,
858 .skip_reinit = 0,
859 .lock_output = STV0299_LOCKOUTPUT_LK,
860 .volt13_op0_op1 = STV0299_VOLT13_OP1,
861 .min_delay_ms = 100,
862 .set_symbol_rate = samsung_smt_7020_stv0299_set_symbol_rate,
863};
864
677static int dvb_register(struct cx8802_dev *dev) 865static int dvb_register(struct cx8802_dev *dev)
678{ 866{
679 struct cx88_core *core = dev->core; 867 struct cx88_core *core = dev->core;
@@ -1203,6 +1391,32 @@ static int dvb_register(struct cx8802_dev *dev)
1203 } 1391 }
1204 break; 1392 break;
1205 } 1393 }
1394 case CX88_BOARD_SAMSUNG_SMT_7020:
1395 dev->ts_gen_cntrl = 0x08;
1396
1397 cx_set(MO_GP0_IO, 0x0101);
1398
1399 cx_clear(MO_GP0_IO, 0x01);
1400 mdelay(100);
1401 cx_set(MO_GP0_IO, 0x01);
1402 mdelay(200);
1403
1404 fe0->dvb.frontend = dvb_attach(stv0299_attach,
1405 &samsung_stv0299_config,
1406 &dev->core->i2c_adap);
1407 if (fe0->dvb.frontend) {
1408 fe0->dvb.frontend->ops.tuner_ops.set_params =
1409 samsung_smt_7020_tuner_set_params;
1410 fe0->dvb.frontend->tuner_priv =
1411 &dev->core->i2c_adap;
1412 fe0->dvb.frontend->ops.set_voltage =
1413 samsung_smt_7020_set_voltage;
1414 fe0->dvb.frontend->ops.set_tone =
1415 samsung_smt_7020_set_tone;
1416 }
1417
1418 break;
1419
1206 default: 1420 default:
1207 printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n", 1421 printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n",
1208 core->name); 1422 core->name);
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index f9fda18b410c..de180d4d5a21 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -192,7 +192,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
192 struct cx88_IR *ir; 192 struct cx88_IR *ir;
193 struct input_dev *input_dev; 193 struct input_dev *input_dev;
194 struct ir_scancode_table *ir_codes = NULL; 194 struct ir_scancode_table *ir_codes = NULL;
195 int ir_type = IR_TYPE_OTHER; 195 u64 ir_type = IR_TYPE_OTHER;
196 int err = -ENOMEM; 196 int err = -ENOMEM;
197 197
198 ir = kzalloc(sizeof(*ir), GFP_KERNEL); 198 ir = kzalloc(sizeof(*ir), GFP_KERNEL);
@@ -383,7 +383,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
383 cx88_ir_start(core, ir); 383 cx88_ir_start(core, ir);
384 384
385 /* all done */ 385 /* all done */
386 err = ir_input_register(ir->input, ir_codes); 386 err = ir_input_register(ir->input, ir_codes, NULL);
387 if (err) 387 if (err)
388 goto err_out_stop; 388 goto err_out_stop;
389 389
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
index bb5104893411..338af77f7f01 100644
--- a/drivers/media/video/cx88/cx88-mpeg.c
+++ b/drivers/media/video/cx88/cx88-mpeg.c
@@ -110,6 +110,9 @@ static int cx8802_start_dma(struct cx8802_dev *dev,
110 case CX88_BOARD_PCHDTV_HD5500: 110 case CX88_BOARD_PCHDTV_HD5500:
111 cx_write(TS_SOP_STAT, 1<<13); 111 cx_write(TS_SOP_STAT, 1<<13);
112 break; 112 break;
113 case CX88_BOARD_SAMSUNG_SMT_7020:
114 cx_write(TS_SOP_STAT, 0x00);
115 break;
113 case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: 116 case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
114 case CX88_BOARD_HAUPPAUGE_NOVASE2_S1: 117 case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
115 cx_write(MO_PINMUX_IO, 0x88); /* Enable MPEG parallel IO and video signal pins */ 118 cx_write(MO_PINMUX_IO, 0x88); /* Enable MPEG parallel IO and video signal pins */
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index b1499bf604ea..48b6c04fb497 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -239,6 +239,7 @@ extern struct sram_channel cx88_sram_channels[];
239#define CX88_BOARD_WINFAST_DTV1800H 81 239#define CX88_BOARD_WINFAST_DTV1800H 81
240#define CX88_BOARD_WINFAST_DTV2000H_J 82 240#define CX88_BOARD_WINFAST_DTV2000H_J 82
241#define CX88_BOARD_PROF_7301 83 241#define CX88_BOARD_PROF_7301 83
242#define CX88_BOARD_SAMSUNG_SMT_7020 84
242 243
243enum cx88_itype { 244enum cx88_itype {
244 CX88_VMUX_COMPOSITE1 = 1, 245 CX88_VMUX_COMPOSITE1 = 1,