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 > > -- Michael Krufky