From 78db854757aa4110f9c6873d1529b851037a3405 Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Tue, 25 Jan 2011 17:04:00 -0300 Subject: [media] Initial commit to support NetUP Dual DVB-T/C CI RF card The card based on cx23885 PCI-e brige. Altera FPGA for CI, multistandard demods stv0367 from STM for QAM & OFDM, Xcieve xc5000 tuners and additional cx25840 for second analog input. Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-dvb.c | 172 ++++++++++++++++++++++++++++-- 1 file changed, 165 insertions(+), 7 deletions(-) (limited to 'drivers/media/video/cx23885/cx23885-dvb.c') diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 5958cb882e9..cf36b9b4794 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -58,6 +58,8 @@ #include "atbm8830.h" #include "ds3000.h" #include "cx23885-f300.h" +#include "altera-ci.h" +#include "stv0367.h" static unsigned int debug; @@ -108,6 +110,22 @@ static void dvb_buf_release(struct videobuf_queue *q, cx23885_free_buffer(q, (struct cx23885_buffer *)vb); } +static void cx23885_dvb_gate_ctrl(struct cx23885_tsport *port, int open) +{ + struct videobuf_dvb_frontends *f; + struct videobuf_dvb_frontend *fe; + + f = &port->frontends; + + if (f->gate <= 1) /* undefined or fe0 */ + fe = videobuf_dvb_get_frontend(f, 1); + else + fe = videobuf_dvb_get_frontend(f, f->gate); + + if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl) + fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, open); +} + static struct videobuf_queue_ops dvb_qops = { .buf_setup = dvb_buf_setup, .buf_prepare = dvb_buf_prepare, @@ -570,12 +588,84 @@ static struct max2165_config mygic_x8558pro_max2165_cfg2 = { .i2c_address = 0x60, .osc_clk = 20 }; +static struct stv0367_config netup_stv0367_config[] = { + { + .demod_address = 0x1c, + .xtal = 27000000, + .if_khz = 4500, + .if_iq_mode = 0, + .ts_mode = 1, + .clk_pol = 0, + }, { + .demod_address = 0x1d, + .xtal = 27000000, + .if_khz = 4500, + .if_iq_mode = 0, + .ts_mode = 1, + .clk_pol = 0, + }, +}; + +static struct xc5000_config netup_xc5000_config[] = { + { + .i2c_address = 0x61, + .if_khz = 4500, + }, { + .i2c_address = 0x64, + .if_khz = 4500, + }, +}; + +int netup_altera_fpga_rw(void *device, int flag, int data, int read) +{ + struct cx23885_dev *dev = (struct cx23885_dev *)device; + unsigned long timeout = jiffies + msecs_to_jiffies(1); + int mem = 0; + + cx_set(MC417_RWD, ALT_RD | ALT_WR | ALT_CS); + if (read) + cx_set(MC417_OEN, ALT_DATA); + else { + cx_clear(MC417_OEN, ALT_DATA);/* D0-D7 out */ + mem = cx_read(MC417_RWD); + mem &= ~ALT_DATA; + mem |= (data & ALT_DATA); + cx_write(MC417_RWD, mem); + } + + if (flag) + cx_set(MC417_RWD, ALT_AD_RG);/* ADDR */ + else + cx_clear(MC417_RWD, ALT_AD_RG);/* VAL */ + + cx_clear(MC417_RWD, ALT_CS);/* ~CS */ + if (read) + cx_clear(MC417_RWD, ALT_RD); + else + cx_clear(MC417_RWD, ALT_WR); + + for (;;) { + mem = cx_read(MC417_RWD); + if ((mem & ALT_RDY) == 0) + break; + if (time_after(jiffies, timeout)) + break; + udelay(1); + } + + cx_set(MC417_RWD, ALT_RD | ALT_WR | ALT_CS); + if (read) + return mem & ALT_DATA; + + return 0; +}; static int dvb_register(struct cx23885_tsport *port) { struct cx23885_dev *dev = port->dev; struct cx23885_i2c *i2c_bus = NULL, *i2c_bus2 = NULL; - struct videobuf_dvb_frontend *fe0; + struct videobuf_dvb_frontend *fe0, *fe1 = NULL; + int mfe_shared = 0; /* bus not shared by default */ int ret; /* Get the first frontend */ @@ -586,6 +676,12 @@ static int dvb_register(struct cx23885_tsport *port) /* init struct videobuf_dvb */ fe0->dvb.name = dev->name; + /* multi-frontend gate control is undefined or defaults to fe0 */ + port->frontends.gate = 0; + + /* Sets the gate control callback to be used by i2c command calls */ + port->gate_ctrl = cx23885_dvb_gate_ctrl; + /* init frontend */ switch (dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1250: @@ -966,20 +1062,61 @@ static int dvb_register(struct cx23885_tsport *port) break; } break; - + case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: + i2c_bus = &dev->i2c_bus[0]; + mfe_shared = 1;/* MFE */ + port->frontends.gate = 0;/* not clear for me yet */ + /* ports B, C */ + /* MFE frontend 1 DVB-T */ + fe0->dvb.frontend = dvb_attach(stv0367ter_attach, + &netup_stv0367_config[port->nr - 1], + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) + if (NULL == dvb_attach(xc5000_attach, + fe0->dvb.frontend, + &i2c_bus->i2c_adap, + &netup_xc5000_config[port->nr - 1])) + goto frontend_detach; + /* MFE frontend 2 */ + fe1 = videobuf_dvb_get_frontend(&port->frontends, 2); + if (fe1 == NULL) + goto frontend_detach; + /* DVB-C init */ + fe1->dvb.frontend = dvb_attach(stv0367cab_attach, + &netup_stv0367_config[port->nr - 1], + &i2c_bus->i2c_adap); + if (fe1->dvb.frontend != NULL) { + fe1->dvb.frontend->id = 1; + if (NULL == dvb_attach(xc5000_attach, + fe1->dvb.frontend, + &i2c_bus->i2c_adap, + &netup_xc5000_config[port->nr - 1])) + goto frontend_detach; + } + break; default: printk(KERN_INFO "%s: The frontend of your DVB/ATSC card " " isn't supported yet\n", dev->name); break; } - if (NULL == fe0->dvb.frontend) { + + if ((NULL == fe0->dvb.frontend) || (fe1 && NULL == fe1->dvb.frontend)) { printk(KERN_ERR "%s: frontend initialization failed\n", - dev->name); - return -1; + dev->name); + goto frontend_detach; } + /* define general-purpose callback pointer */ fe0->dvb.frontend->callback = cx23885_tuner_callback; + if (fe1) + fe1->dvb.frontend->callback = cx23885_tuner_callback; +#if 0 + /* Ensure all frontends negotiate bus access */ + fe0->dvb.frontend->ops.ts_bus_ctrl = cx23885_dvb_bus_ctrl; + if (fe1) + fe1->dvb.frontend->ops.ts_bus_ctrl = cx23885_dvb_bus_ctrl; +#endif /* Put the analog decoder in standby to keep it quiet */ call_all(dev, core, s_power, 0); @@ -989,10 +1126,10 @@ static int dvb_register(struct cx23885_tsport *port) /* register everything */ ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port, - &dev->pci->dev, adapter_nr, 0, + &dev->pci->dev, adapter_nr, mfe_shared, cx23885_dvb_fe_ioctl_override); if (ret) - return ret; + goto frontend_detach; /* init CI & MAC */ switch (dev->board) { @@ -1008,6 +1145,17 @@ static int dvb_register(struct cx23885_tsport *port) netup_ci_init(port); break; } + case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: { + struct altera_ci_config netup_ci_cfg = { + .dev = dev,/* magic number to identify*/ + .adapter = &port->frontends.adapter,/* for CI */ + .demux = &fe0->dvb.demux,/* for hw pid filter */ + .fpga_rw = netup_altera_fpga_rw, + }; + + altera_ci_init(&netup_ci_cfg, port->nr); + break; + } case CX23885_BOARD_TEVII_S470: { u8 eeprom[256]; /* 24C02 i2c eeprom */ @@ -1024,6 +1172,11 @@ static int dvb_register(struct cx23885_tsport *port) } return ret; + +frontend_detach: + port->gate_ctrl = NULL; + videobuf_dvb_dealloc_frontends(&port->frontends); + return -EINVAL; } int cx23885_dvb_register(struct cx23885_tsport *port) @@ -1100,8 +1253,13 @@ int cx23885_dvb_unregister(struct cx23885_tsport *port) case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: netup_ci_exit(port); break; + case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: + altera_ci_release(port->dev, port->nr); + break; } + port->gate_ctrl = NULL; + return 0; } -- cgit v1.2.3-70-g09d2 From d164460f897e2ae8c48ca28c763bb1233d180e7e Mon Sep 17 00:00:00 2001 From: Abylay Ospan Date: Sun, 2 Jan 2011 09:10:00 -0300 Subject: [media] cx23885: Altera FPGA CI interface reworked It decreases I2C traffic. Signed-off-by: Abylay Ospan Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-dvb.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/media/video/cx23885/cx23885-dvb.c') diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index cf36b9b4794..c0e66550675 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -620,29 +620,29 @@ int netup_altera_fpga_rw(void *device, int flag, int data, int read) { struct cx23885_dev *dev = (struct cx23885_dev *)device; unsigned long timeout = jiffies + msecs_to_jiffies(1); - int mem = 0; + uint32_t mem = 0; - cx_set(MC417_RWD, ALT_RD | ALT_WR | ALT_CS); + mem = cx_read(MC417_RWD); if (read) cx_set(MC417_OEN, ALT_DATA); else { cx_clear(MC417_OEN, ALT_DATA);/* D0-D7 out */ - mem = cx_read(MC417_RWD); mem &= ~ALT_DATA; mem |= (data & ALT_DATA); - cx_write(MC417_RWD, mem); } if (flag) - cx_set(MC417_RWD, ALT_AD_RG);/* ADDR */ + mem |= ALT_AD_RG; else - cx_clear(MC417_RWD, ALT_AD_RG);/* VAL */ + mem &= ~ALT_AD_RG; - cx_clear(MC417_RWD, ALT_CS);/* ~CS */ + mem &= ~ALT_CS; if (read) - cx_clear(MC417_RWD, ALT_RD); + mem = (mem & ~ALT_RD) | ALT_WR; else - cx_clear(MC417_RWD, ALT_WR); + mem = (mem & ~ALT_WR) | ALT_RD; + + cx_write(MC417_RWD, mem); /* start RW cycle */ for (;;) { mem = cx_read(MC417_RWD); -- cgit v1.2.3-70-g09d2 From 4174ebf5ebd7a09589ff8ff3bc3246ea0a9bd356 Mon Sep 17 00:00:00 2001 From: Abylay Ospan Date: Sun, 2 Jan 2011 09:15:00 -0300 Subject: [media] Force xc5000 firmware loading for NetUP Dual DVB-T/C CI RF card Two xc5000 tuners connected to same i2c bus. Experiments shows that situation when one tuner is not initialized while other is tuned to channel causes TS errors. Signed-off-by: Abylay Ospan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-dvb.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/media/video/cx23885/cx23885-dvb.c') diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index c0e66550675..3c315f94cc8 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -1071,12 +1071,15 @@ static int dvb_register(struct cx23885_tsport *port) fe0->dvb.frontend = dvb_attach(stv0367ter_attach, &netup_stv0367_config[port->nr - 1], &i2c_bus->i2c_adap); - if (fe0->dvb.frontend != NULL) + if (fe0->dvb.frontend != NULL) { if (NULL == dvb_attach(xc5000_attach, fe0->dvb.frontend, &i2c_bus->i2c_adap, &netup_xc5000_config[port->nr - 1])) goto frontend_detach; + /* load xc5000 firmware */ + fe0->dvb.frontend->ops.tuner_ops.init(fe0->dvb.frontend); + } /* MFE frontend 2 */ fe1 = videobuf_dvb_get_frontend(&port->frontends, 2); if (fe1 == NULL) -- cgit v1.2.3-70-g09d2