diff options
Diffstat (limited to 'drivers/media/video/em28xx/em28xx-dvb.c')
-rw-r--r-- | drivers/media/video/em28xx/em28xx-dvb.c | 117 |
1 files changed, 81 insertions, 36 deletions
diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c index e5916dee4094..cef7a2d409cb 100644 --- a/drivers/media/video/em28xx/em28xx-dvb.c +++ b/drivers/media/video/em28xx/em28xx-dvb.c @@ -42,6 +42,8 @@ #include "cxd2820r.h" #include "tda18271c2dd.h" #include "drxk.h" +#include "tda10071.h" +#include "a8293.h" MODULE_DESCRIPTION("driver for em28xx based DVB cards"); MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); @@ -122,7 +124,7 @@ static inline void print_err_status(struct em28xx *dev, } } -static inline int dvb_isoc_copy(struct em28xx *dev, struct urb *urb) +static inline int em28xx_dvb_isoc_copy(struct em28xx *dev, struct urb *urb) { int i; @@ -155,7 +157,7 @@ static inline int dvb_isoc_copy(struct em28xx *dev, struct urb *urb) return 0; } -static int start_streaming(struct em28xx_dvb *dvb) +static int em28xx_start_streaming(struct em28xx_dvb *dvb) { int rc; struct em28xx *dev = dvb->adapter.priv; @@ -175,10 +177,10 @@ static int start_streaming(struct em28xx_dvb *dvb) return em28xx_init_isoc(dev, EM28XX_DVB_MAX_PACKETS, EM28XX_DVB_NUM_BUFS, max_dvb_packet_size, - dvb_isoc_copy); + em28xx_dvb_isoc_copy); } -static int stop_streaming(struct em28xx_dvb *dvb) +static int em28xx_stop_streaming(struct em28xx_dvb *dvb) { struct em28xx *dev = dvb->adapter.priv; @@ -189,7 +191,7 @@ static int stop_streaming(struct em28xx_dvb *dvb) return 0; } -static int start_feed(struct dvb_demux_feed *feed) +static int em28xx_start_feed(struct dvb_demux_feed *feed) { struct dvb_demux *demux = feed->demux; struct em28xx_dvb *dvb = demux->priv; @@ -203,7 +205,7 @@ static int start_feed(struct dvb_demux_feed *feed) rc = dvb->nfeeds; if (dvb->nfeeds == 1) { - ret = start_streaming(dvb); + ret = em28xx_start_streaming(dvb); if (ret < 0) rc = ret; } @@ -212,7 +214,7 @@ static int start_feed(struct dvb_demux_feed *feed) return rc; } -static int stop_feed(struct dvb_demux_feed *feed) +static int em28xx_stop_feed(struct dvb_demux_feed *feed) { struct dvb_demux *demux = feed->demux; struct em28xx_dvb *dvb = demux->priv; @@ -222,7 +224,7 @@ static int stop_feed(struct dvb_demux_feed *feed) dvb->nfeeds--; if (0 == dvb->nfeeds) - err = stop_streaming(dvb); + err = em28xx_stop_streaming(dvb); mutex_unlock(&dvb->lock); return err; @@ -380,7 +382,7 @@ static void terratec_h5_init(struct em28xx *dev) em28xx_gpio_set(dev, terratec_h5_end); }; -static int mt352_terratec_xs_init(struct dvb_frontend *fe) +static int em28xx_mt352_terratec_xs_init(struct dvb_frontend *fe) { /* Values extracted from a USB trace of the Terratec Windows driver */ static u8 clock_config[] = { CLOCK_CTL, 0x38, 0x2c }; @@ -412,7 +414,7 @@ static struct mt352_config terratec_xs_mt352_cfg = { .demod_address = (0x1e >> 1), .no_tuner = 1, .if2 = 45600, - .demod_init = mt352_terratec_xs_init, + .demod_init = em28xx_mt352_terratec_xs_init, }; static struct tda10023_config em28xx_tda10023_config = { @@ -438,11 +440,25 @@ static struct cxd2820r_config em28xx_cxd2820r_config = { static struct tda18271_config em28xx_cxd2820r_tda18271_config = { .output_opt = TDA18271_OUTPUT_LT_OFF, + .gate = TDA18271_GATE_DIGITAL, +}; + +static const struct tda10071_config em28xx_tda10071_config = { + .i2c_address = 0x55, /* (0xaa >> 1) */ + .i2c_wr_max = 64, + .ts_mode = TDA10071_TS_SERIAL, + .spec_inv = 0, + .xtal = 40444000, /* 40.444 MHz */ + .pll_multiplier = 20, +}; + +static const struct a8293_config em28xx_a8293_config = { + .i2c_addr = 0x08, /* (0x10 >> 1) */ }; /* ------------------------------------------------------------------ */ -static int attach_xc3028(u8 addr, struct em28xx *dev) +static int em28xx_attach_xc3028(u8 addr, struct em28xx *dev) { struct dvb_frontend *fe; struct xc2028_config cfg; @@ -472,10 +488,8 @@ static int attach_xc3028(u8 addr, struct em28xx *dev) /* ------------------------------------------------------------------ */ -static int register_dvb(struct em28xx_dvb *dvb, - struct module *module, - struct em28xx *dev, - struct device *device) +static int em28xx_register_dvb(struct em28xx_dvb *dvb, struct module *module, + struct em28xx *dev, struct device *device) { int result; @@ -522,8 +536,8 @@ static int register_dvb(struct em28xx_dvb *dvb, dvb->demux.priv = dvb; dvb->demux.filternum = 256; dvb->demux.feednum = 256; - dvb->demux.start_feed = start_feed; - dvb->demux.stop_feed = stop_feed; + dvb->demux.start_feed = em28xx_start_feed; + dvb->demux.stop_feed = em28xx_stop_feed; result = dvb_dmx_init(&dvb->demux); if (result < 0) { @@ -591,7 +605,7 @@ fail_adapter: return result; } -static void unregister_dvb(struct em28xx_dvb *dvb) +static void em28xx_unregister_dvb(struct em28xx_dvb *dvb) { dvb_net_release(&dvb->net); dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); @@ -607,9 +621,9 @@ static void unregister_dvb(struct em28xx_dvb *dvb) dvb_unregister_adapter(&dvb->adapter); } -static int dvb_init(struct em28xx *dev) +static int em28xx_dvb_init(struct em28xx *dev) { - int result = 0; + int result = 0, mfe_shared = 0; struct em28xx_dvb *dvb; if (!dev->board.has_dvb) { @@ -648,7 +662,7 @@ static int dvb_init(struct em28xx *dev) dvb->fe[0] = dvb_attach(lgdt330x_attach, &em2880_lgdt3303_dev, &dev->i2c_adap); - if (attach_xc3028(0x61, dev) < 0) { + if (em28xx_attach_xc3028(0x61, dev) < 0) { result = -EINVAL; goto out_free; } @@ -657,7 +671,7 @@ static int dvb_init(struct em28xx *dev) dvb->fe[0] = dvb_attach(zl10353_attach, &em28xx_zl10353_with_xc3028, &dev->i2c_adap); - if (attach_xc3028(0x61, dev) < 0) { + if (em28xx_attach_xc3028(0x61, dev) < 0) { result = -EINVAL; goto out_free; } @@ -668,7 +682,7 @@ static int dvb_init(struct em28xx *dev) dvb->fe[0] = dvb_attach(zl10353_attach, &em28xx_zl10353_xc3028_no_i2c_gate, &dev->i2c_adap); - if (attach_xc3028(0x61, dev) < 0) { + if (em28xx_attach_xc3028(0x61, dev) < 0) { result = -EINVAL; goto out_free; } @@ -689,7 +703,7 @@ static int dvb_init(struct em28xx *dev) &dev->i2c_adap); } - if (attach_xc3028(0x61, dev) < 0) { + if (em28xx_attach_xc3028(0x61, dev) < 0) { result = -EINVAL; goto out_free; } @@ -699,7 +713,7 @@ static int dvb_init(struct em28xx *dev) dvb->fe[0] = dvb_attach(s5h1409_attach, &em28xx_s5h1409_with_xc3028, &dev->i2c_adap); - if (attach_xc3028(0x61, dev) < 0) { + if (em28xx_attach_xc3028(0x61, dev) < 0) { result = -EINVAL; goto out_free; } @@ -720,7 +734,7 @@ static int dvb_init(struct em28xx *dev) case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E: dvb->fe[0] = dvb_attach(drxd_attach, &em28xx_drxd, NULL, &dev->i2c_adap, &dev->udev->dev); - if (attach_xc3028(0x61, dev) < 0) { + if (em28xx_attach_xc3028(0x61, dev) < 0) { result = -EINVAL; goto out_free; } @@ -753,11 +767,9 @@ static int dvb_init(struct em28xx *dev) dvb->fe[0] = dvb_attach(cxd2820r_attach, &em28xx_cxd2820r_config, &dev->i2c_adap, NULL); if (dvb->fe[0]) { - struct i2c_adapter *i2c_tuner; - i2c_tuner = cxd2820r_get_tuner_i2c_adapter(dvb->fe[0]); /* FE 0 attach tuner */ if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60, - i2c_tuner, &em28xx_cxd2820r_tda18271_config)) { + &dev->i2c_adap, &em28xx_cxd2820r_tda18271_config)) { dvb_frontend_detach(dvb->fe[0]); result = -EINVAL; goto out_free; @@ -768,10 +780,12 @@ static int dvb_init(struct em28xx *dev) dvb->fe[1]->id = 1; /* FE 1 attach tuner */ if (!dvb_attach(tda18271_attach, dvb->fe[1], 0x60, - i2c_tuner, &em28xx_cxd2820r_tda18271_config)) { + &dev->i2c_adap, &em28xx_cxd2820r_tda18271_config)) { dvb_frontend_detach(dvb->fe[1]); /* leave FE 0 still active */ } + + mfe_shared = 1; } break; case EM2884_BOARD_TERRATEC_H5: @@ -809,6 +823,16 @@ static int dvb_init(struct em28xx *dev) sizeof(dvb->fe[0]->ops.tuner_ops)); break; + case EM28174_BOARD_PCTV_460E: + /* attach demod */ + dvb->fe[0] = dvb_attach(tda10071_attach, + &em28xx_tda10071_config, &dev->i2c_adap); + + /* attach SEC */ + if (dvb->fe[0]) + dvb_attach(a8293_attach, dvb->fe[0], &dev->i2c_adap, + &em28xx_a8293_config); + break; default: em28xx_errdev("/2: The frontend of your DVB/ATSC card" " isn't supported yet\n"); @@ -823,11 +847,14 @@ static int dvb_init(struct em28xx *dev) dvb->fe[0]->callback = em28xx_tuner_callback; /* register everything */ - result = register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev); + result = em28xx_register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev); if (result < 0) goto out_free; + /* MFE lock */ + dvb->adapter.mfe_shared = mfe_shared; + em28xx_info("Successfully loaded em28xx-dvb\n"); ret: em28xx_set_mode(dev, EM28XX_SUSPEND); @@ -840,7 +867,14 @@ out_free: goto ret; } -static int dvb_fini(struct em28xx *dev) +static inline void prevent_sleep(struct dvb_frontend_ops *ops) +{ + ops->set_voltage = NULL; + ops->sleep = NULL; + ops->tuner_ops.sleep = NULL; +} + +static int em28xx_dvb_fini(struct em28xx *dev) { if (!dev->board.has_dvb) { /* This device does not support the extension */ @@ -848,8 +882,19 @@ static int dvb_fini(struct em28xx *dev) } if (dev->dvb) { - unregister_dvb(dev->dvb); - kfree(dev->dvb); + struct em28xx_dvb *dvb = dev->dvb; + + if (dev->state & DEV_DISCONNECTED) { + /* We cannot tell the device to sleep + * once it has been unplugged. */ + if (dvb->fe[0]) + prevent_sleep(&dvb->fe[0]->ops); + if (dvb->fe[1]) + prevent_sleep(&dvb->fe[1]->ops); + } + + em28xx_unregister_dvb(dvb); + kfree(dvb); dev->dvb = NULL; } @@ -859,8 +904,8 @@ static int dvb_fini(struct em28xx *dev) static struct em28xx_ops dvb_ops = { .id = EM28XX_DVB, .name = "Em28xx dvb Extension", - .init = dvb_init, - .fini = dvb_fini, + .init = em28xx_dvb_init, + .fini = em28xx_dvb_fini, }; static int __init em28xx_dvb_register(void) |