I glanced at the 3303 part of the driver and I think is reasonable to combine them. I have not examined the card level stuff yet. Give me a couple of days and I'll post a patch everyone can try. -- Mac On Sunday 10 July 2005 01:16 am, Michael Krufky wrote: > Tylor and Mac- > > Check out this web page: > > http://www.fortetw.com/en/Product_vsb.htm > > ... It has the following: > > << > The VSB/QAM Receiver is a highly upgraded single chip > that supports both ATSC terrestrial and digital cable > broadcast environment. The LGDT3302 and LGDT3303 enable > to demodulate, equalize, and correct signals of ATSC > compliant 8/16 VSB and ITU-T J.83 Annex B,C compliant > 64/256 QAM > > [ LGDT3302 ] > - ATSC compliant 8/16 VSB and MMDS 2/4/6/8/16 VSB > receiver - ITU-T J.83 Annex B compliant 64/256 Qam > receiver - Integrated 10-bit A/D converter > - Parallel/serial MPEG-2 transport interface > - Support I2C bus interface > - Embedded 64KB SRAM for VSB and 64/256 QAM > - Supports 44MHz IF input as well as 6MHz IF input > - 100 TQFP > [ LGDT3303 ] > - 5th Generation VSB/QAM receiver > - Enhanced Multi-Ghost cancellation > - Pin-to-pin compatable with LGDT3302 > > > This last line makes me think that these two drivers can > be combined into a single LGDT330X module.... What do you > guys think? > > I also saw the following in Google cache, (website > deleted), if anyone reading the list is interested: > > << > The VSB/QAM receiver (LGDT3302) is a highly upgraded > single chip that supports both north American digital > terrestrial broadcast television and digital cable > television standards. This LGDT3302 enables to > demodulate, equalize and correct signals of ATSC > compliant 8/16 VSB and ITU-T J.83 Annex B compliant > 64/256 QAM. > > The 10-bit ADC is integrated in this chip in order to > simplify system design and achieve better performance. > The LGDT3302 accepts a VSB or QAM modulated analog signal > of 44MHz IF or 6MHz low IF, which is sampled by 25MHz > clock, and delivers a transport stream by parallel or > serial. > > The 64 KB SRAM is embedded to support all modes of > de-interleaving in 64/256 QAM. There is no need to use > external memory for de-interleaver. > > The thermal characteristics of the former product, > Advanced VSB receiver (LGDT3301), has been confirmed > already in several products and become an unique feature > of our chips. This attribute is materialized with this > new chip too. > > ATSC compliant 8/16 VSB and MMDS 2/4/8/16 VSB receiver > > ITU-T J.83 Annex B compliant 64/256 QAM receiver > > Integrated 10-bit A/D converter > > (supports for optional external A/D converter) > > All digital demodulation > > Parallel/serial MPEG-2 transport interface > > Supports I2C bus interface > > Boundary Scan test circuit complies to the IEEE > Std.1149.1 > > Highly integrated solution for the lowest system cost > > Embedded 64KB SRAM for VSB and 64/256QAM > (No need to use external de-interleaver SRAM) > > Supports 44MHz IF input as well as low IF input(6MHz) > 100 pin TQFP > > Operating voltage(I/O, Core): 3.3V, 1.8V > > Taylor Jacob wrote: > >This patch adds support for the LGDT3303 VSB/QAM > > chipset. I used the > > same SNR > > >code as the LGDT3302 chipset that was recently added to > > cvs. Any > > questions > > >please feel free to ask. This will add support for the > > BBTI Air2PC > > card due to > > >ship very soon that utilizes this chipset. > > > >Taylor Jacob > > > > > > > >/* > > Support for BBTI Technisat Air2PC - ATSC - 3rd Gen > > > > Copyright (C) 2005 Taylor Jacob > > <rtjacob@xxxxxxxxxxxxx> > > > > 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 <linux/init.h> > >#include <linux/module.h> > >#include <linux/moduleparam.h> > >#include <linux/device.h> > >#include <linux/kernel.h> > >#include <asm/div64.h> > > > >#include "dvb_frontend.h" > >#include "lgdt3303.h" > > > >struct lgdt3303_state { > > > > struct i2c_adapter* i2c; > > struct dvb_frontend_ops ops; > > const struct lgdt3303_config* config; > > struct dvb_frontend frontend; > > u8 current_modulation; > > > > /* demodulator private data */ > > u8 initialised:1; > >}; > > > >static int debug; > >#define dprintk(args...) \ > > do { \ > > if (debug) printk(KERN_DEBUG "lgdt3303: " > > args); \ } while (0) > > > >static int i2c_writebytes (struct lgdt3303_state* > > state, u8 reg, u8 > > *buf, u8 len) > > >{ > > /* probbably a much better way or doing this */ > > u8 buf2 [256],x; > > int err; > > struct i2c_msg msg = { .addr = > > state->config->demod_address, > > .flags = 0, .buf = buf2, .len = len + 1 }; > > > buf2[0] = reg; > > for (x = 0 ; x < len ; x++) > > buf2[x+1] = buf[x]; > > > > if ((err = i2c_transfer (state->i2c, &msg, 1)) != > > 1) { printk ("%s: i2c write error (addr %02x, err == > > %i)\n", __FUNCTION__, state->config->demod_address, > > err); return -EREMOTEIO; > > } > > > > return 0; > >} > > > >static int i2c_tunerwritebytes (struct lgdt3303_state* > > state, u8 *buf, > > u8 len) > > >{ > > /* probbably a much better way or doing this */ > > int err; > > struct i2c_msg msg = { .addr = > > state->config->tuner_address, > > .flags = 0, .buf = buf, .len = len }; > > > if ((err = i2c_transfer (state->i2c, &msg, 1)) != > > 1) { printk ("%s: i2c write error (addr %02x, err == > > %i)\n", __FUNCTION__, state->config->demod_address, > > err); return -EREMOTEIO; > > } > > > > return 0; > >} > > > >static u8 i2c_readbytes (struct lgdt3303_state* state, > > u8 reg, u8* > > buf, u8 len) > > >{ > > u8 reg2 [] = { reg }; > > > > struct i2c_msg msg [] = { { .addr = > > state->config->demod_address, > > .flags = 0, .buf = reg2, .len = 1 }, > > > { .addr = state->config->demod_address, > > .flags = I2C_M_RD, > > .buf = buf, .len = len } }; > > > int err; > > > > if ((err = i2c_transfer (state->i2c, msg, 2)) != 2) > > { printk ("%s: i2c read error (addr %02x, err == > > %i)\n", __FUNCTION__, state->config->demod_address, > > err); return -EREMOTEIO; > > } > > > > return 0; > >} > > > >static void lgdt3303_soft_reset(struct lgdt3303_state* > > state) { > > u8 buf; > > dprintk("%s\n", __FUNCTION__); > > > > buf = 0x00; > > i2c_writebytes(state,0x02,&buf,1); > > > > buf = 0x01; > > i2c_writebytes(state,0x02,&buf,1); > > > > return; > >} > > > >static int lgdt3303_setup_frontend_parameters (struct > > dvb_frontend* fe, struct dvb_frontend_parameters *p) { > > struct lgdt3303_state* state = > > fe->demodulator_priv; u32 freq = 0; > > u16 tunerfreq = 0; > > u8 buf[6]; > > > > freq = 44000000 + p->frequency; > > > > > > tunerfreq = freq / 62500; > > > > buf[0] = (tunerfreq >> 8) & 0x7F; > > buf[1] = (tunerfreq & 0xFF); > > buf[2] = 0x86; > > > > if (p->frequency < 160000000) { > > buf[3] = 0x01; > > } else if (p->frequency > 445000000) { > > buf[3] = 0x04; > > } else { > > buf[3] = 0x02; > > } > > > > /* Cut and paste from BBTI Windows driver > > Important? */ buf[4] = buf[2] | 0x18; > > buf[5] = 0x50; > > > > i2c_tunerwritebytes(state,buf,4); > > > > i2c_tunerwritebytes(state,&buf[4],2); > > > > /* invert clock */ > > buf[0] = 0xF3; > > i2c_writebytes(state,0x87,buf,1); > > > > state->current_modulation = p->u.vsb.modulation; > > > > switch (p->u.vsb.modulation) > > { > > case VSB_8: > > buf[0] = 0x03; > > i2c_writebytes(state,0x00,buf,1); > > buf[0] = 0x40; > > i2c_writebytes(state,0x0d,buf,1); > > buf[0] = 0x87; > > i2c_writebytes(state,0x0e,buf,1); > > buf[0] = 0x8e; > > i2c_writebytes(state,0x0f,buf,1); > > buf[0] = 0x01; > > i2c_writebytes(state,0x10,buf,1); > > buf[0] = 0x88; > > i2c_writebytes(state,0x47,buf,1); > > buf[0] = 0x14; > > i2c_writebytes(state,0x4c,buf,1); > > break; > > > > case QAM_64: > > buf[0] = 0x00; > > i2c_writebytes(state,0x00,buf,1); > > i2c_writebytes(state,0x0d,buf,1); > > i2c_writebytes(state,0x0e,buf,1); > > i2c_writebytes(state,0x0f,buf,1); > > i2c_writebytes(state,0x10,buf,1); > > buf[0] = 0x63; > > i2c_writebytes(state,0x51,buf,1); > > buf[0] = 0x66; > > i2c_writebytes(state,0x47,buf,1); > > buf[0] = 0x66; > > i2c_writebytes(state,0x48,buf,1); > > buf[0] = 0x1a; > > i2c_writebytes(state,0x4d,buf,1); > > buf[0] = 0x14; > > i2c_writebytes(state,0x4c,buf,1); > > buf[0] = 0x08; > > i2c_writebytes(state,0x49,buf,1); > > buf[0] = 0x9b; > > i2c_writebytes(state,0x4a,buf,1); > > break; > > > > case QAM_256: > > buf[0] = 0x01; > > i2c_writebytes(state,0x00,buf,1); > > buf[0] = 0x00; > > i2c_writebytes(state,0x0d,buf,1); > > i2c_writebytes(state,0x0e,buf,1); > > i2c_writebytes(state,0x0f,buf,1); > > i2c_writebytes(state,0x10,buf,1); > > buf[0] = 0x63; > > i2c_writebytes(state,0x51,buf,1); > > buf[0] = 0x66; > > i2c_writebytes(state,0x47,buf,1); > > buf[0] = 0x66; > > i2c_writebytes(state,0x48,buf,1); > > buf[0] = 0x1a; > > i2c_writebytes(state,0x4d,buf,1); > > buf[0] = 0x14; > > i2c_writebytes(state,0x4c,buf,1); > > buf[0] = 0x08; > > i2c_writebytes(state,0x49,buf,1); > > buf[0] = 0x9b; > > i2c_writebytes(state,0x4a,buf,1); > > break; > > default: > > break; > > } > > > > lgdt3303_soft_reset(state); > > > > return 0; > >} > > > >static int lgdt3303_read_status(struct dvb_frontend* > > fe, fe_status_t* > > status) > > >{ > > struct lgdt3303_state* state = > > fe->demodulator_priv; u8 lock; > > *status = 0; > > > > i2c_readbytes(state,0x1C,&lock,1); > > if (lock & 0x80) { > > *status |= FE_HAS_SIGNAL; > > *status |= FE_HAS_CARRIER; > > } > > > > i2c_readbytes(state,0x58,&lock,1); > > if (lock & 0x01) { > > *status |= FE_HAS_VITERBI; > > } > > > > if (lock & 0x02) { > > *status |= FE_HAS_SYNC; > > *status |= FE_HAS_LOCK; > > } > > return 0; > >} > > > >static int lgdt3303_read_ber(struct dvb_frontend* fe, > > u32* ber) { > > > > /* Not implimented in frontend */ > > *ber = 0; > > > > return 0; > >} > > > >static int lgdt3303_read_signal_strength(struct > > dvb_frontend* fe, u16* > > strength) > > >{ > > struct lgdt3303_state* state = > > fe->demodulator_priv; u8 b[] = {0,0,0}; > > u16 temp = 0; > > > > i2c_readbytes(state,0x52,&b[0],1); > > i2c_readbytes(state,0x54,&b[1],1); > > > > /* This math was given from example from the > > windows bbti driver */ temp = 1700 - ((b[0] & 0x07) << > > 8 | b[1]); > > > > *strength = temp * (0xFFFF/1700); > > > > return 0; > >} > > > >static int lgdt3303_read_snr(struct dvb_frontend* fe, > > u16* snr) { > > > > struct lgdt3303_state* state = > > fe->demodulator_priv; u8 b[] = {0,0,0}; > > u32 noise = 0; > > > > /* This code cut and pasted from the LGDT3302.C > > driver and ought * to be put in a common place at some > > point */ > > > > /* > > * Spec sheet shows formula for SNR_EQ = 10 > > log10(25 * 24**2 / noise) * and SNR_PH = 10 log10(25 * > > 32**2 / noise) for equalizer and > > phase tracker > > > * respectively. The following tables are built on > > these formulas. * The usual definition is SNR = 20 > > log10(signal/noise) * If the specification is wrong > > the value retuned is 1/2 the > > actual SNR in db. > > > * > > * This table is a an ordered list of noise values > > computed by the * formula from the spec sheet such > > that the index into the table * starting at 43 or 45 > > is the SNR value in db. There are > > duplicate noise > > > * value entries at the beginning because the SNR > > varies more than * 1 db for a change of 1 digit in > > noise at very small values of > > noise. > > > * > > * Examples from SNR_EQ table: > > * noise SNR > > * 0 43 > > * 1 42 > > * 2 39 > > * 3 37 > > * 4 36 > > * 5 35 > > * 6 34 > > * 7 33 > > * 8 33 > > * 9 32 > > * 10 32 > > * 11 31 > > * 12 31 > > * 13 30 > > */ > > > > static const u32 SNR_EQ[] = > > { 1, 2, 2, 2, 3, 3, 4, > > 4, > > 5, 7, > > > 9, 11, 13, 17, 21, 26, > > 33, 41, > > 52, 65, > > > 81, 102, 129, 162, 204, 257, > > 323, 406, > > 511, 644, > > > 810, 1020, 1284, 1616, 2035, 2561, > > 3224, 4059, > > 5110, 6433, > > > 8098, 10195, 12835, 16158, 20341, 25608, > > 32238, 40585, > > 51094, 64323, > > > 80978, 101945, 128341, 161571, 203406, > > 256073, 0x40000 }; > > > > static const u32 SNR_PH[] = > > { 1, 2, 2, 2, 3, 3, > > 4, 5, > > 6, 8, > > > 10, 12, 15, 19, 23, 29, > > 37, 46, > > 58, 73, > > > 91, 115, 144, 182, 229, 288, > > 362, 456, > > 574, 722, > > > 909, 1144, 1440, 1813, 2282, 2873, > > 3617, 4553, > > 5732, 7216, > > > 9084, 11436, 14396, 18124, 22817, 28724, > > 36161, 45524, > > 57312, 72151, > > > 90833, 114351, 143960, 181235, 228161, > > 0x040000 }; > > > > static u32 snr_db; /* index into SNR_EQ[] */ > > > > if (state->current_modulation == VSB_8) { > > > > /* Equalizer Mean-Square Error Register for VSB > > */ > > > > i2c_readbytes(state,0x6E,&b[0],1); > > i2c_readbytes(state,0x71,&b[1],1); > > i2c_readbytes(state,0x72,&b[2],1); > > > > noise = ((b[0] & 0x07) << 16) | (b[1] << 8) | > > b[2]; > > > > /* > > * Look up noise value in table. > > * A better search algorithm could be used... > > * watch out there are duplicate entries. > > */ > > for (snr_db = 0; snr_db < sizeof(SNR_EQ); > > snr_db++) { if (noise < SNR_EQ[snr_db]) { > > *snr = (43 - snr_db) * (0xFFFF/43); > > > > break; > > } > > } > > } else { > > /* Phase Tracker Mean-Square Error Register for > > QAM */ > > > > i2c_readbytes(state,0x6F,&b[0],1); > > i2c_readbytes(state,0x70,&b[1],1); > > i2c_readbytes(state,0x71,&b[2],1); > > noise = ((b[0] & 7<<3) << 13) | (b[1] << 8) | > > b[2]; > > > > /* Look up noise value in table. */ > > for (snr_db = 0; snr_db < sizeof(SNR_PH); > > snr_db++) { if (noise < SNR_PH[snr_db]) { > > *snr = (45 - snr_db) * (0xFFFF/45); > > break; > > } > > } > > } > > > > return 0; > >} > > > >static int lgdt3303_read_ucblocks(struct dvb_frontend* > > fe, u32* ucblocks) { > > struct lgdt3303_state* state = > > fe->demodulator_priv; u8 b[] = {0,0,0}; > > > > i2c_readbytes(state,0x8B,&b[0],1); > > i2c_readbytes(state,0x8C,&b[1],1); > > > > *ucblocks = (b[0] << 8) | b[1]; > > > > return 0; > >} > > > >static int lgdt3303_sleep(struct dvb_frontend* fe) > >{ > > return 0; > >} > > > >static int lgdt3303_init(struct dvb_frontend* fe) > >{ > > return 0; > >} > > > >static int lgdt3303_get_tune_settings(struct > > dvb_frontend* fe, struct > > dvb_frontend_tune_settings* fesettings) > > >{ > > fesettings->min_delay_ms = 500; > > fesettings->step_size = 0; > > fesettings->max_drift = 0; > > return 0; > >} > > > >static void lgdt3303_release(struct dvb_frontend* fe) > >{ > > struct lgdt3303_state* state = > > fe->demodulator_priv; kfree(state); > >} > > > >static struct dvb_frontend_ops lgdt3303_ops; > > > >struct dvb_frontend* lgdt3303_attach(const struct > > lgdt3303_config* config, struct i2c_adapter* i2c) > >{ > > struct lgdt3303_state* state = NULL; > > u8 buf = 0; > > > > /* allocate memory for the internal state */ > > state = kmalloc(sizeof(struct lgdt3303_state), > > GFP_KERNEL); if (state == NULL) goto error; > > > > /* setup the state */ > > state->config = config; > > state->i2c = i2c; > > state->current_modulation = VSB_8; > > memcpy(&state->ops, &lgdt3303_ops, sizeof(struct > > dvb_frontend_ops)); > > > > i2c_readbytes(state, 0x85, &buf, 1); > > if (buf != 0x20) goto error; > > > > i2c_readbytes(state, 0x86, &buf, 1); > > if (buf != 0x40) goto error; > > > > /* create dvb_frontend */ > > state->frontend.ops = &state->ops; > > state->frontend.demodulator_priv = state; > > return &state->frontend; > > > >error: > > kfree(state); > > return NULL; > >} > > > >static struct dvb_frontend_ops lgdt3303_ops = { > > > > .info = { > > .name = "LGDT3303 VSB/QAM frontend", > > .type = FE_ATSC, > > .frequency_min = 54000000, > > .frequency_max = 860000000, > > /* stepsize is just a guess */ > > .frequency_stepsize = 166666, > > .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | > > FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | > > FE_CAN_FEC_AUTO | FE_CAN_8VSB | FE_CAN_QAM_64 | > > FE_CAN_QAM_256 }, > > > > .release = lgdt3303_release, > > > > .init = lgdt3303_init, > > .sleep = lgdt3303_sleep, > > > > .set_frontend = lgdt3303_setup_frontend_parameters, > > .get_tune_settings = lgdt3303_get_tune_settings, > > > > .read_status = lgdt3303_read_status, > > .read_ber = lgdt3303_read_ber, > > .read_signal_strength = > > lgdt3303_read_signal_strength, .read_snr = > > lgdt3303_read_snr, > > .read_ucblocks = lgdt3303_read_ucblocks, > > > >}; > > > >module_param(debug, int, 0644); > >MODULE_PARM_DESC(debug, "Turn on/off frontend debugging > > (default:off)."); > > > >MODULE_DESCRIPTION("LGDT3303 ATSC (8VSB & ITU J83 > > AnnexB FEC > > QAM64/256) demodulator driver"); > > >MODULE_AUTHOR("Taylor Jacob"); > >MODULE_LICENSE("GPL"); > > > >EXPORT_SYMBOL(lgdt3303_attach); > > > > > > > >/* > > Driver for the LGDT3303 demodulator > >*/ > > > >#ifndef LGDT3303_H > >#define LGDT3303_H > > > >#include <linux/dvb/frontend.h> > > > >struct lgdt3303_config > >{ > > /* the demodulator's i2c address */ > > u8 demod_address; > > u8 tuner_address; > > > >}; > > > >extern struct dvb_frontend* lgdt3303_attach(const > > struct > > lgdt3303_config* config, > > > struct i2c_adapter* i2c); > > > >#endif // LGDT3303_H