diff options
Diffstat (limited to 'drivers/media/video/cx231xx/cx231xx-dvb.c')
-rw-r--r-- | drivers/media/video/cx231xx/cx231xx-dvb.c | 250 |
1 files changed, 223 insertions, 27 deletions
diff --git a/drivers/media/video/cx231xx/cx231xx-dvb.c b/drivers/media/video/cx231xx/cx231xx-dvb.c index 4ea3776b39fb..5feb3ee640d9 100644 --- a/drivers/media/video/cx231xx/cx231xx-dvb.c +++ b/drivers/media/video/cx231xx/cx231xx-dvb.c | |||
@@ -29,6 +29,10 @@ | |||
29 | 29 | ||
30 | #include "xc5000.h" | 30 | #include "xc5000.h" |
31 | #include "dvb_dummy_fe.h" | 31 | #include "dvb_dummy_fe.h" |
32 | #include "s5h1432.h" | ||
33 | #include "tda18271.h" | ||
34 | #include "s5h1411.h" | ||
35 | #include "lgdt3305.h" | ||
32 | 36 | ||
33 | MODULE_DESCRIPTION("driver for cx231xx based DVB cards"); | 37 | MODULE_DESCRIPTION("driver for cx231xx based DVB cards"); |
34 | MODULE_AUTHOR("Srinivasa Deevi <srinivasa.deevi@conexant.com>"); | 38 | MODULE_AUTHOR("Srinivasa Deevi <srinivasa.deevi@conexant.com>"); |
@@ -65,6 +69,72 @@ struct cx231xx_dvb { | |||
65 | struct dvb_net net; | 69 | struct dvb_net net; |
66 | }; | 70 | }; |
67 | 71 | ||
72 | static struct s5h1432_config dvico_s5h1432_config = { | ||
73 | .output_mode = S5H1432_SERIAL_OUTPUT, | ||
74 | .gpio = S5H1432_GPIO_ON, | ||
75 | .qam_if = S5H1432_IF_4000, | ||
76 | .vsb_if = S5H1432_IF_4000, | ||
77 | .inversion = S5H1432_INVERSION_OFF, | ||
78 | .status_mode = S5H1432_DEMODLOCKING, | ||
79 | .mpeg_timing = S5H1432_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, | ||
80 | }; | ||
81 | |||
82 | static struct tda18271_std_map cnxt_rde253s_tda18271_std_map = { | ||
83 | .dvbt_6 = { .if_freq = 4000, .agc_mode = 3, .std = 4, | ||
84 | .if_lvl = 1, .rfagc_top = 0x37, }, | ||
85 | .dvbt_7 = { .if_freq = 4000, .agc_mode = 3, .std = 5, | ||
86 | .if_lvl = 1, .rfagc_top = 0x37, }, | ||
87 | .dvbt_8 = { .if_freq = 4000, .agc_mode = 3, .std = 6, | ||
88 | .if_lvl = 1, .rfagc_top = 0x37, }, | ||
89 | }; | ||
90 | |||
91 | static struct tda18271_config cnxt_rde253s_tunerconfig = { | ||
92 | .std_map = &cnxt_rde253s_tda18271_std_map, | ||
93 | .gate = TDA18271_GATE_ANALOG, | ||
94 | }; | ||
95 | |||
96 | static struct s5h1411_config tda18271_s5h1411_config = { | ||
97 | .output_mode = S5H1411_SERIAL_OUTPUT, | ||
98 | .gpio = S5H1411_GPIO_OFF, | ||
99 | .vsb_if = S5H1411_IF_3250, | ||
100 | .qam_if = S5H1411_IF_4000, | ||
101 | .inversion = S5H1411_INVERSION_ON, | ||
102 | .status_mode = S5H1411_DEMODLOCKING, | ||
103 | .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, | ||
104 | }; | ||
105 | static struct s5h1411_config xc5000_s5h1411_config = { | ||
106 | .output_mode = S5H1411_SERIAL_OUTPUT, | ||
107 | .gpio = S5H1411_GPIO_OFF, | ||
108 | .vsb_if = S5H1411_IF_3250, | ||
109 | .qam_if = S5H1411_IF_3250, | ||
110 | .inversion = S5H1411_INVERSION_OFF, | ||
111 | .status_mode = S5H1411_DEMODLOCKING, | ||
112 | .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, | ||
113 | }; | ||
114 | |||
115 | static struct lgdt3305_config hcw_lgdt3305_config = { | ||
116 | .i2c_addr = 0x0e, | ||
117 | .mpeg_mode = LGDT3305_MPEG_SERIAL, | ||
118 | .tpclk_edge = LGDT3305_TPCLK_FALLING_EDGE, | ||
119 | .tpvalid_polarity = LGDT3305_TP_VALID_HIGH, | ||
120 | .deny_i2c_rptr = 1, | ||
121 | .spectral_inversion = 1, | ||
122 | .qam_if_khz = 4000, | ||
123 | .vsb_if_khz = 3250, | ||
124 | }; | ||
125 | |||
126 | static struct tda18271_std_map hauppauge_tda18271_std_map = { | ||
127 | .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 4, | ||
128 | .if_lvl = 1, .rfagc_top = 0x58, }, | ||
129 | .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 5, | ||
130 | .if_lvl = 1, .rfagc_top = 0x58, }, | ||
131 | }; | ||
132 | |||
133 | static struct tda18271_config hcw_tda18271_config = { | ||
134 | .std_map = &hauppauge_tda18271_std_map, | ||
135 | .gate = TDA18271_GATE_DIGITAL, | ||
136 | }; | ||
137 | |||
68 | static inline void print_err_status(struct cx231xx *dev, int packet, int status) | 138 | static inline void print_err_status(struct cx231xx *dev, int packet, int status) |
69 | { | 139 | { |
70 | char *errmsg = "Unknown"; | 140 | char *errmsg = "Unknown"; |
@@ -128,11 +198,33 @@ static inline int dvb_isoc_copy(struct cx231xx *dev, struct urb *urb) | |||
128 | continue; | 198 | continue; |
129 | } | 199 | } |
130 | 200 | ||
131 | dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer + | 201 | dvb_dmx_swfilter(&dev->dvb->demux, |
132 | urb->iso_frame_desc[i].offset, | 202 | urb->transfer_buffer + |
133 | urb->iso_frame_desc[i].actual_length); | 203 | urb->iso_frame_desc[i].offset, |
204 | urb->iso_frame_desc[i].actual_length); | ||
205 | } | ||
206 | |||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | static inline int dvb_bulk_copy(struct cx231xx *dev, struct urb *urb) | ||
211 | { | ||
212 | if (!dev) | ||
213 | return 0; | ||
214 | |||
215 | if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) | ||
216 | return 0; | ||
217 | |||
218 | if (urb->status < 0) { | ||
219 | print_err_status(dev, -1, urb->status); | ||
220 | if (urb->status == -ENOENT) | ||
221 | return 0; | ||
134 | } | 222 | } |
135 | 223 | ||
224 | /* Feed the transport payload into the kernel demux */ | ||
225 | dvb_dmx_swfilter(&dev->dvb->demux, | ||
226 | urb->transfer_buffer, urb->actual_length); | ||
227 | |||
136 | return 0; | 228 | return 0; |
137 | } | 229 | } |
138 | 230 | ||
@@ -141,21 +233,44 @@ static int start_streaming(struct cx231xx_dvb *dvb) | |||
141 | int rc; | 233 | int rc; |
142 | struct cx231xx *dev = dvb->adapter.priv; | 234 | struct cx231xx *dev = dvb->adapter.priv; |
143 | 235 | ||
144 | usb_set_interface(dev->udev, 0, 1); | 236 | if (dev->USE_ISO) { |
145 | rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE); | 237 | cx231xx_info("DVB transfer mode is ISO.\n"); |
146 | if (rc < 0) | 238 | mutex_lock(&dev->i2c_lock); |
147 | return rc; | 239 | cx231xx_enable_i2c_port_3(dev, false); |
240 | cx231xx_set_alt_setting(dev, INDEX_TS1, 4); | ||
241 | cx231xx_enable_i2c_port_3(dev, true); | ||
242 | mutex_unlock(&dev->i2c_lock); | ||
243 | rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE); | ||
244 | if (rc < 0) | ||
245 | return rc; | ||
246 | dev->mode_tv = 1; | ||
247 | return cx231xx_init_isoc(dev, CX231XX_DVB_MAX_PACKETS, | ||
248 | CX231XX_DVB_NUM_BUFS, | ||
249 | dev->ts1_mode.max_pkt_size, | ||
250 | dvb_isoc_copy); | ||
251 | } else { | ||
252 | cx231xx_info("DVB transfer mode is BULK.\n"); | ||
253 | cx231xx_set_alt_setting(dev, INDEX_TS1, 0); | ||
254 | rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE); | ||
255 | if (rc < 0) | ||
256 | return rc; | ||
257 | dev->mode_tv = 1; | ||
258 | return cx231xx_init_bulk(dev, CX231XX_DVB_MAX_PACKETS, | ||
259 | CX231XX_DVB_NUM_BUFS, | ||
260 | dev->ts1_mode.max_pkt_size, | ||
261 | dvb_bulk_copy); | ||
262 | } | ||
148 | 263 | ||
149 | return cx231xx_init_isoc(dev, CX231XX_DVB_MAX_PACKETS, | ||
150 | CX231XX_DVB_NUM_BUFS, | ||
151 | CX231XX_DVB_MAX_PACKETSIZE, dvb_isoc_copy); | ||
152 | } | 264 | } |
153 | 265 | ||
154 | static int stop_streaming(struct cx231xx_dvb *dvb) | 266 | static int stop_streaming(struct cx231xx_dvb *dvb) |
155 | { | 267 | { |
156 | struct cx231xx *dev = dvb->adapter.priv; | 268 | struct cx231xx *dev = dvb->adapter.priv; |
157 | 269 | ||
158 | cx231xx_uninit_isoc(dev); | 270 | if (dev->USE_ISO) |
271 | cx231xx_uninit_isoc(dev); | ||
272 | else | ||
273 | cx231xx_uninit_bulk(dev); | ||
159 | 274 | ||
160 | cx231xx_set_mode(dev, CX231XX_SUSPEND); | 275 | cx231xx_set_mode(dev, CX231XX_SUSPEND); |
161 | 276 | ||
@@ -216,7 +331,11 @@ static int cx231xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire) | |||
216 | 331 | ||
217 | static struct xc5000_config cnxt_rde250_tunerconfig = { | 332 | static struct xc5000_config cnxt_rde250_tunerconfig = { |
218 | .i2c_address = 0x61, | 333 | .i2c_address = 0x61, |
219 | .if_khz = 5380, | 334 | .if_khz = 4000, |
335 | }; | ||
336 | static struct xc5000_config cnxt_rdu250_tunerconfig = { | ||
337 | .i2c_address = 0x61, | ||
338 | .if_khz = 3250, | ||
220 | }; | 339 | }; |
221 | 340 | ||
222 | /* ------------------------------------------------------------------ */ | 341 | /* ------------------------------------------------------------------ */ |
@@ -228,7 +347,7 @@ static int attach_xc5000(u8 addr, struct cx231xx *dev) | |||
228 | struct xc5000_config cfg; | 347 | struct xc5000_config cfg; |
229 | 348 | ||
230 | memset(&cfg, 0, sizeof(cfg)); | 349 | memset(&cfg, 0, sizeof(cfg)); |
231 | cfg.i2c_adap = &dev->i2c_bus[1].i2c_adap; | 350 | cfg.i2c_adap = &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap; |
232 | cfg.i2c_addr = addr; | 351 | cfg.i2c_addr = addr; |
233 | 352 | ||
234 | if (!dev->dvb->frontend) { | 353 | if (!dev->dvb->frontend) { |
@@ -268,7 +387,6 @@ int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq) | |||
268 | /*params.audmode = ; */ | 387 | /*params.audmode = ; */ |
269 | 388 | ||
270 | /* Set the analog parameters to set the frequency */ | 389 | /* Set the analog parameters to set the frequency */ |
271 | cx231xx_info("Setting Frequency for XC5000\n"); | ||
272 | dops->set_analog_params(dev->dvb->frontend, ¶ms); | 390 | dops->set_analog_params(dev->dvb->frontend, ¶ms); |
273 | } | 391 | } |
274 | 392 | ||
@@ -445,19 +563,21 @@ static int dvb_init(struct cx231xx *dev) | |||
445 | dev->cx231xx_set_analog_freq = cx231xx_set_analog_freq; | 563 | dev->cx231xx_set_analog_freq = cx231xx_set_analog_freq; |
446 | dev->cx231xx_reset_analog_tuner = cx231xx_reset_analog_tuner; | 564 | dev->cx231xx_reset_analog_tuner = cx231xx_reset_analog_tuner; |
447 | 565 | ||
566 | mutex_lock(&dev->lock); | ||
448 | cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE); | 567 | cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE); |
568 | cx231xx_demod_reset(dev); | ||
449 | /* init frontend */ | 569 | /* init frontend */ |
450 | switch (dev->model) { | 570 | switch (dev->model) { |
571 | case CX231XX_BOARD_CNXT_CARRAERA: | ||
451 | case CX231XX_BOARD_CNXT_RDE_250: | 572 | case CX231XX_BOARD_CNXT_RDE_250: |
452 | 573 | ||
453 | /* dev->dvb->frontend = dvb_attach(s5h1411_attach, | 574 | dev->dvb->frontend = dvb_attach(s5h1432_attach, |
454 | &dvico_s5h1411_config, | 575 | &dvico_s5h1432_config, |
455 | &dev->i2c_bus[1].i2c_adap); */ | 576 | &dev->i2c_bus[dev->board.demod_i2c_master].i2c_adap); |
456 | dev->dvb->frontend = dvb_attach(dvb_dummy_fe_ofdm_attach); | ||
457 | 577 | ||
458 | if (dev->dvb->frontend == NULL) { | 578 | if (dev->dvb->frontend == NULL) { |
459 | printk(DRIVER_NAME | 579 | printk(DRIVER_NAME |
460 | ": Failed to attach dummy front end\n"); | 580 | ": Failed to attach s5h1432 front end\n"); |
461 | result = -EINVAL; | 581 | result = -EINVAL; |
462 | goto out_free; | 582 | goto out_free; |
463 | } | 583 | } |
@@ -466,16 +586,19 @@ static int dvb_init(struct cx231xx *dev) | |||
466 | dvb->frontend->callback = cx231xx_tuner_callback; | 586 | dvb->frontend->callback = cx231xx_tuner_callback; |
467 | 587 | ||
468 | if (!dvb_attach(xc5000_attach, dev->dvb->frontend, | 588 | if (!dvb_attach(xc5000_attach, dev->dvb->frontend, |
469 | &dev->i2c_bus[1].i2c_adap, | 589 | &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap, |
470 | &cnxt_rde250_tunerconfig)) { | 590 | &cnxt_rde250_tunerconfig)) { |
471 | result = -EINVAL; | 591 | result = -EINVAL; |
472 | goto out_free; | 592 | goto out_free; |
473 | } | 593 | } |
474 | 594 | ||
475 | break; | 595 | break; |
596 | case CX231XX_BOARD_CNXT_SHELBY: | ||
476 | case CX231XX_BOARD_CNXT_RDU_250: | 597 | case CX231XX_BOARD_CNXT_RDU_250: |
477 | 598 | ||
478 | dev->dvb->frontend = dvb_attach(dvb_dummy_fe_ofdm_attach); | 599 | dev->dvb->frontend = dvb_attach(s5h1411_attach, |
600 | &xc5000_s5h1411_config, | ||
601 | &dev->i2c_bus[dev->board.demod_i2c_master].i2c_adap); | ||
479 | 602 | ||
480 | if (dev->dvb->frontend == NULL) { | 603 | if (dev->dvb->frontend == NULL) { |
481 | printk(DRIVER_NAME | 604 | printk(DRIVER_NAME |
@@ -488,12 +611,82 @@ static int dvb_init(struct cx231xx *dev) | |||
488 | dvb->frontend->callback = cx231xx_tuner_callback; | 611 | dvb->frontend->callback = cx231xx_tuner_callback; |
489 | 612 | ||
490 | if (!dvb_attach(xc5000_attach, dev->dvb->frontend, | 613 | if (!dvb_attach(xc5000_attach, dev->dvb->frontend, |
491 | &dev->i2c_bus[1].i2c_adap, | 614 | &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap, |
492 | &cnxt_rde250_tunerconfig)) { | 615 | &cnxt_rdu250_tunerconfig)) { |
616 | result = -EINVAL; | ||
617 | goto out_free; | ||
618 | } | ||
619 | break; | ||
620 | case CX231XX_BOARD_CNXT_RDE_253S: | ||
621 | |||
622 | dev->dvb->frontend = dvb_attach(s5h1432_attach, | ||
623 | &dvico_s5h1432_config, | ||
624 | &dev->i2c_bus[dev->board.demod_i2c_master].i2c_adap); | ||
625 | |||
626 | if (dev->dvb->frontend == NULL) { | ||
627 | printk(DRIVER_NAME | ||
628 | ": Failed to attach s5h1432 front end\n"); | ||
629 | result = -EINVAL; | ||
630 | goto out_free; | ||
631 | } | ||
632 | |||
633 | /* define general-purpose callback pointer */ | ||
634 | dvb->frontend->callback = cx231xx_tuner_callback; | ||
635 | |||
636 | if (!dvb_attach(tda18271_attach, dev->dvb->frontend, | ||
637 | 0x60, &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap, | ||
638 | &cnxt_rde253s_tunerconfig)) { | ||
639 | result = -EINVAL; | ||
640 | goto out_free; | ||
641 | } | ||
642 | break; | ||
643 | case CX231XX_BOARD_CNXT_RDU_253S: | ||
644 | |||
645 | dev->dvb->frontend = dvb_attach(s5h1411_attach, | ||
646 | &tda18271_s5h1411_config, | ||
647 | &dev->i2c_bus[dev->board.demod_i2c_master].i2c_adap); | ||
648 | |||
649 | if (dev->dvb->frontend == NULL) { | ||
650 | printk(DRIVER_NAME | ||
651 | ": Failed to attach dummy front end\n"); | ||
652 | result = -EINVAL; | ||
653 | goto out_free; | ||
654 | } | ||
655 | |||
656 | /* define general-purpose callback pointer */ | ||
657 | dvb->frontend->callback = cx231xx_tuner_callback; | ||
658 | |||
659 | if (!dvb_attach(tda18271_attach, dev->dvb->frontend, | ||
660 | 0x60, &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap, | ||
661 | &cnxt_rde253s_tunerconfig)) { | ||
493 | result = -EINVAL; | 662 | result = -EINVAL; |
494 | goto out_free; | 663 | goto out_free; |
495 | } | 664 | } |
496 | break; | 665 | break; |
666 | case CX231XX_BOARD_HAUPPAUGE_EXETER: | ||
667 | |||
668 | printk(KERN_INFO "%s: looking for tuner / demod on i2c bus: %d\n", | ||
669 | __func__, i2c_adapter_id(&dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap)); | ||
670 | |||
671 | dev->dvb->frontend = dvb_attach(lgdt3305_attach, | ||
672 | &hcw_lgdt3305_config, | ||
673 | &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap); | ||
674 | |||
675 | if (dev->dvb->frontend == NULL) { | ||
676 | printk(DRIVER_NAME | ||
677 | ": Failed to attach LG3305 front end\n"); | ||
678 | result = -EINVAL; | ||
679 | goto out_free; | ||
680 | } | ||
681 | |||
682 | /* define general-purpose callback pointer */ | ||
683 | dvb->frontend->callback = cx231xx_tuner_callback; | ||
684 | |||
685 | dvb_attach(tda18271_attach, dev->dvb->frontend, | ||
686 | 0x60, &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap, | ||
687 | &hcw_tda18271_config); | ||
688 | break; | ||
689 | |||
497 | 690 | ||
498 | default: | 691 | default: |
499 | printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card" | 692 | printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card" |
@@ -513,15 +706,18 @@ static int dvb_init(struct cx231xx *dev) | |||
513 | if (result < 0) | 706 | if (result < 0) |
514 | goto out_free; | 707 | goto out_free; |
515 | 708 | ||
516 | cx231xx_set_mode(dev, CX231XX_SUSPEND); | 709 | |
517 | printk(KERN_INFO "Successfully loaded cx231xx-dvb\n"); | 710 | printk(KERN_INFO "Successfully loaded cx231xx-dvb\n"); |
518 | return 0; | ||
519 | 711 | ||
520 | out_free: | 712 | ret: |
521 | cx231xx_set_mode(dev, CX231XX_SUSPEND); | 713 | cx231xx_set_mode(dev, CX231XX_SUSPEND); |
714 | mutex_unlock(&dev->lock); | ||
715 | return result; | ||
716 | |||
717 | out_free: | ||
522 | kfree(dvb); | 718 | kfree(dvb); |
523 | dev->dvb = NULL; | 719 | dev->dvb = NULL; |
524 | return result; | 720 | goto ret; |
525 | } | 721 | } |
526 | 722 | ||
527 | static int dvb_fini(struct cx231xx *dev) | 723 | static int dvb_fini(struct cx231xx *dev) |