/* Mantis PCI bridge driver Copyright (C) 2005 Manu Abraham (manu@kromtek.com) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include "mantis_common.h" #include "mantis_core.h" #include "dmxdev.h" #include "dvbdev.h" #include "dvb_demux.h" #include "dvb_frontend.h" #include "stv0299.h" /* 0x01, 0x15, 0x02, 0x00, // 0x30 0x03, 0x00, 0x04, 0x2a, // 0x7d 0x05, 0x85, // 0x35 0x06, 0x02, 0x07, 0x00, 0x08, 0x00, // 0xc3 0x0C, 0x01, // 0x00 0x0D, 0x81, 0x0E, 0x23, // 0x23 0x0F, 0x12, // 0x12 0x10, 0x7e, // 0x7e 0x11, 0x84, 0x12, 0xB9, 0x13, 0x88, // 0x88 0x14, 0x89, // 0x89 0x15, 0xC9, 0x16, 0x00, // 0x00 0x17, 0x5c, // 0x5c 0x18, 0x00, // 0x00 0x19, 0x00, // 0x00 0x1A, 0x00, 0x1C, 0x00, 0x1D, 0x00, 0x1E, 0x00, 0x1F, 0x3A, 0x20, 0x2E, 0x21, 0x80, 0x22, 0xFF, 0x23, 0xC1, 0x28, 0x00, 0x29, 0x1E, 0x2A, 0x14, 0x2B, 0x0F, 0x2C, 0x09, 0x2D, 0x05, 0x31, 0x1F, 0x32, 0x19, 0x33, 0xFE, 0x34, 0x93, 0xff, 0xff, */ static u8 lgtdqcs001f_inittab[] = { 0x01, 0x15, 0x02, 0x00, 0x03, 0x00, 0x04, 0x2a, 0x05, 0x85, 0x06, 0x02, 0x07, 0x00, 0x08, 0x00, 0x0c, 0x01, 0x0d, 0x81, 0x0e, 0x44, // 0x0f, 0x14, 0x0f, 0x94, 0x10, 0x3c, 0x11, 0x84, 0x12, 0xb9, 0x13, 0xb5, 0x14, 0x4f, 0x15, 0xc9, 0x16, 0x80, 0x17, 0x36, 0x18, 0xfb, 0x19, 0xcf, 0x1a, 0xbc, 0x1c, 0x2b, 0x1d, 0x27, 0x1e, 0x00, 0x1f, 0x0b, 0x20, 0xa1, 0x21, 0x60, 0x22, 0x00, 0x23, 0x00, 0x28, 0x00, 0x29, 0x28, 0x2a, 0x14, 0x2b, 0x0f, 0x2c, 0x09, 0x2d, 0x05, 0x31, 0x1f, 0x32, 0x19, 0x33, 0xfc, 0x34, 0x13, 0xff, 0xff, }; static int lgtdqcs001f_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params) { u8 buf[4]; u32 div; struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; // struct i2c_msg msg_r = { .addr = 0x61, .flags = I2C_M_RD, .buf = buf, .len = 1 }; div = params->frequency / 250; buf[0] = (div >> 8) & 0x7f; buf[1] = div & 0xff; buf[2] = 0x83; buf[3] = 0xc0; if (params->frequency < 1531000) buf[3] |= 0x04; else buf[3] &= ~0x04; if (i2c_transfer(i2c, &msg, 4) < 0) { dprintk(verbose, MANTIS_ERROR, 1, "Write: I2C Transfer failed"); return -EIO; } msleep(100); /* if (i2c_transfer(i2c, &msg_r, 1) < 0) { dprintk(verbose, MANTIS_ERROR, 1, "Read: I2C Transfer failed"); return -EIO; } dprintk(verbose, MANTIS_ERROR, 1, "TSA5059 read=[0x%02x]", buf[0]); */ return 0; } static int lgtdqcs001f_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio) { u8 aclk = 0; u8 bclk = 0; if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; } else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; } else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; } else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; } else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; } else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; } stv0299_writereg (fe, 0x13, aclk); stv0299_writereg (fe, 0x14, bclk); stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff); stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff); stv0299_writereg (fe, 0x21, (ratio ) & 0xf0); return 0; } static struct stv0299_config lgtdqcs001f_config = { .demod_address = 0x68, .inittab = lgtdqcs001f_inittab, .mclk = 88000000UL, // .invert = 0, .invert = 1, // .enhanced_tuning = 0, .skip_reinit = 0, .lock_output = STV0229_LOCKOUTPUT_0, .volt13_op0_op1 = STV0299_VOLT13_OP0, .min_delay_ms = 100, .set_symbol_rate = lgtdqcs001f_set_symbol_rate, .pll_set = lgtdqcs001f_pll_set, }; static int mantis_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed) { struct dvb_demux *dvbdmx = dvbdmxfeed->demux; struct mantis_pci *mantis = dvbdmx->priv; dprintk(verbose, MANTIS_DEBUG, 1, "Mantis DVB Start feed"); if (!dvbdmx->dmx.frontend) { dprintk(verbose, MANTIS_DEBUG, 1, "no frontend ?"); return -EINVAL; } mantis->feeds++; dprintk(verbose, MANTIS_DEBUG, 1, "mantis start feed, feeds=%d", mantis->feeds); if (mantis->feeds == 1) { dprintk(verbose, MANTIS_DEBUG, 1, "mantis start feed & dma"); mantis_dma_start(mantis); } return mantis->feeds; } static int mantis_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) { struct dvb_demux *dvbdmx = dvbdmxfeed->demux; struct mantis_pci *mantis = dvbdmx->priv; dprintk(verbose, MANTIS_DEBUG, 1, "Mantis DVB Stop feed"); if (!dvbdmx->dmx.frontend) { dprintk(verbose, MANTIS_DEBUG, 1, "no frontend ?"); return -EINVAL; } mantis->feeds--; if (mantis->feeds == 0) { dprintk(verbose, MANTIS_DEBUG, 1, "mantis stop feed and dma"); mantis_dma_stop(mantis); } return 0; } int __devinit mantis_dvb_init(struct mantis_pci *mantis) { int result; dprintk(verbose, MANTIS_DEBUG, 1, "dvb_register_adapter"); if (dvb_register_adapter(&mantis->dvb_adapter, "Mantis dvb adapter", THIS_MODULE) < 0) { dprintk(verbose, MANTIS_ERROR, 1, "Error registering adapter"); return -ENODEV; } mantis->dvb_adapter.priv = mantis; mantis->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING; mantis->demux.priv = mantis; mantis->demux.filternum = 256; mantis->demux.feednum = 256; mantis->demux.start_feed = mantis_dvb_start_feed; mantis->demux.stop_feed = mantis_dvb_stop_feed; mantis->demux.write_to_decoder = NULL; mantis->ts_size = 1; dprintk(verbose, MANTIS_DEBUG, 1, "dvb_dmx_init"); if ((result = dvb_dmx_init(&mantis->demux)) < 0) { dprintk(verbose, MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result); goto err0; } mantis->dmxdev.filternum = 256; mantis->dmxdev.demux = &mantis->demux.dmx; mantis->dmxdev.capabilities = 0; dprintk(verbose, MANTIS_DEBUG, 1, "dvb_dmxdev_init"); if ((result = dvb_dmxdev_init(&mantis->dmxdev, &mantis->dvb_adapter)) < 0) { dprintk(verbose, MANTIS_ERROR, 1, "dvb_dmxdev_init failed, ERROR=%d", result); goto err1; } mantis->fe_hw.source = DMX_FRONTEND_0; if ((result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_hw)) < 0) { dprintk(verbose, MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result); goto err2; } mantis->fe_mem.source = DMX_MEMORY_FE; if ((result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_mem)) < 0) { dprintk(verbose, MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result); goto err3; } if ((result = mantis->demux.dmx.connect_frontend(&mantis->demux.dmx, &mantis->fe_hw)) < 0) { dprintk(verbose, MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result); goto err4; } dvb_net_init(&mantis->dvb_adapter, &mantis->dvbnet, &mantis->demux.dmx); tasklet_init(&mantis->tasklet, mantis_dma_xfer, (unsigned long) mantis); mantis_frontend_init(mantis); return 0; /* * Error conditions .. */ err4: mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem); err3: mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw); err2: dvb_dmxdev_release(&mantis->dmxdev); err1: dvb_dmx_release(&mantis->demux); err0: dvb_unregister_adapter(&mantis->dvb_adapter); return result; } int __devinit mantis_frontend_init(struct mantis_pci *mantis) { dprintk(verbose, MANTIS_DEBUG, 1, "Mantis frontend Init"); mantis_fe_powerup(mantis); switch (mantis->sub_device_id) { case 0x0016: /* VP-1033 */ dprintk(verbose, MANTIS_DEBUG, 1, "Searching for a STV0299 (DVB-S) frontend"); mantis->fe = stv0299_attach(&lgtdqcs001f_config, &mantis->adapter); if (mantis->fe) { dprintk(verbose, MANTIS_DEBUG, 1, "Mantis DVB-S STV0299 frontend attach success"); dprintk(verbose, MANTIS_ERROR, 1, "found STV0299 DVB-S frontend @ 0x%02x", lgtdqcs001f_config.demod_address); } break; default: dprintk(verbose, MANTIS_DEBUG, 1, "Unknown frontend type:[0x%02x]", mantis->sub_device_id); return -ENODEV; } if (mantis->fe == NULL) dprintk(verbose, MANTIS_ERROR, 1, "A frontend was not found for the device"); else { if (dvb_register_frontend(&mantis->dvb_adapter, mantis->fe)) { dprintk(verbose, MANTIS_ERROR, 1, "ERROR: Frontend registration failed"); if (mantis->fe->ops->release) mantis->fe->ops->release(mantis->fe); mantis->fe = NULL; return -ENODEV; } } return 0; } int __devexit mantis_dvb_exit(struct mantis_pci *mantis) { tasklet_kill(&mantis->tasklet); dvb_net_release(&mantis->dvbnet); mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem); mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw); dvb_dmxdev_release(&mantis->dmxdev); dvb_dmx_release(&mantis->demux); if (mantis->fe) dvb_unregister_frontend(mantis->fe); dprintk(verbose, MANTIS_DEBUG, 1, "dvb_unregister_adapter"); dvb_unregister_adapter(&mantis->dvb_adapter); return 0; }