aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/dvb
diff options
context:
space:
mode:
authorMac Michaels <wmichaels1@earthlink.net>2005-07-07 20:58:29 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-07-07 21:24:02 -0400
commitd8667cbbe440aacb246832afc217a6a44664115c (patch)
tree29c68e5317355c398c0de99d5d665fa653384cef /drivers/media/dvb
parent25de192660627e1e8dc8ee6a120ff8b54d108593 (diff)
[PATCH] dvb: frontend: add driver for LGDT3302
Add support for LGDT3302 (ATSC VSB/QAM) used in DViCO FusionHDTV3 Gold. Signed-off-by: Mac Michaels <wmichaels1@earthlink.net> Signed-off-by: Michael Krufky <mkrufky@m1k.net> Signed-off-by: Johannes Stezenbach <js@linuxtv.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/media/dvb')
-rw-r--r--drivers/media/dvb/frontends/Kconfig7
-rw-r--r--drivers/media/dvb/frontends/Makefile1
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.c13
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.h1
-rw-r--r--drivers/media/dvb/frontends/lgdt3302.c618
-rw-r--r--drivers/media/dvb/frontends/lgdt3302.h49
-rw-r--r--drivers/media/dvb/frontends/lgdt3302_priv.h72
7 files changed, 761 insertions, 0 deletions
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index 5c695937e2ad..d847c62bd837 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -187,4 +187,11 @@ config DVB_BCM3510
187 An ATSC 8VSB/16VSB and QAM64/256 tuner module. Say Y when you want to 187 An ATSC 8VSB/16VSB and QAM64/256 tuner module. Say Y when you want to
188 support this frontend. 188 support this frontend.
189 189
190config DVB_LGDT3302
191 tristate "LGDT3302 based (DViCO FusionHDTV3 Gold)"
192 depends on DVB_CORE
193 help
194 An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
195 to support this frontend.
196
190endmenu 197endmenu
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 8d46dd721f45..de5e240cba7f 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -30,3 +30,4 @@ obj-$(CONFIG_DVB_OR51211) += or51211.o
30obj-$(CONFIG_DVB_OR51132) += or51132.o 30obj-$(CONFIG_DVB_OR51132) += or51132.o
31obj-$(CONFIG_DVB_BCM3510) += bcm3510.o 31obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
32obj-$(CONFIG_DVB_S5H1420) += s5h1420.o 32obj-$(CONFIG_DVB_S5H1420) += s5h1420.o
33obj-$(CONFIG_DVB_LGDT3302) += lgdt3302.o
diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c
index 8be143b7ce4c..71e06ec7925a 100644
--- a/drivers/media/dvb/frontends/dvb-pll.c
+++ b/drivers/media/dvb/frontends/dvb-pll.c
@@ -93,6 +93,19 @@ struct dvb_pll_desc dvb_pll_lg_z201 = {
93}; 93};
94EXPORT_SYMBOL(dvb_pll_lg_z201); 94EXPORT_SYMBOL(dvb_pll_lg_z201);
95 95
96struct dvb_pll_desc dvb_pll_microtune_4042 = {
97 .name = "Microtune 4042 FI5",
98 .min = 57000000,
99 .max = 858000000,
100 .count = 3,
101 .entries = {
102 { 162000000, 44000000, 62500, 0x8e, 0xa1 },
103 { 457000000, 44000000, 62500, 0x8e, 0x91 },
104 { 999999999, 44000000, 62500, 0x8e, 0x31 },
105 },
106};
107EXPORT_SYMBOL(dvb_pll_microtune_4042);
108
96struct dvb_pll_desc dvb_pll_unknown_1 = { 109struct dvb_pll_desc dvb_pll_unknown_1 = {
97 .name = "unknown 1", /* used by dntv live dvb-t */ 110 .name = "unknown 1", /* used by dntv live dvb-t */
98 .min = 174000000, 111 .min = 174000000,
diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h
index 57b64ffee402..98312bfe59d0 100644
--- a/drivers/media/dvb/frontends/dvb-pll.h
+++ b/drivers/media/dvb/frontends/dvb-pll.h
@@ -24,6 +24,7 @@ extern struct dvb_pll_desc dvb_pll_thomson_dtt7579;
24extern struct dvb_pll_desc dvb_pll_thomson_dtt759x; 24extern struct dvb_pll_desc dvb_pll_thomson_dtt759x;
25extern struct dvb_pll_desc dvb_pll_thomson_dtt7610; 25extern struct dvb_pll_desc dvb_pll_thomson_dtt7610;
26extern struct dvb_pll_desc dvb_pll_lg_z201; 26extern struct dvb_pll_desc dvb_pll_lg_z201;
27extern struct dvb_pll_desc dvb_pll_microtune_4042;
27extern struct dvb_pll_desc dvb_pll_unknown_1; 28extern struct dvb_pll_desc dvb_pll_unknown_1;
28 29
29extern struct dvb_pll_desc dvb_pll_tua6010xs; 30extern struct dvb_pll_desc dvb_pll_tua6010xs;
diff --git a/drivers/media/dvb/frontends/lgdt3302.c b/drivers/media/dvb/frontends/lgdt3302.c
new file mode 100644
index 000000000000..d0b91219cf6e
--- /dev/null
+++ b/drivers/media/dvb/frontends/lgdt3302.c
@@ -0,0 +1,618 @@
1/*
2 * $Id: lgdt3302.c,v 1.2 2005/06/28 23:50:48 mkrufky Exp $
3 *
4 * Support for LGDT3302 (DViCO FustionHDTV 3 Gold) - VSB/QAM
5 *
6 * Copyright (C) 2005 Wilson Michaels <wilsonmichaels@earthlink.net>
7 *
8 * Based on code from Kirk Lapray <kirk_lapray@bigfoot.com>
9 * Copyright (C) 2005
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28 * NOTES ABOUT THIS DRIVER
29 *
30 * This driver supports DViCO FusionHDTV 3 Gold under Linux.
31 *
32 * TODO:
33 * BER and signal strength always return 0.
34 *
35 */
36
37#include <linux/version.h>
38#include <linux/kernel.h>
39#include <linux/module.h>
40#include <linux/moduleparam.h>
41#include <linux/init.h>
42#include <linux/delay.h>
43#include <asm/byteorder.h>
44
45#include "dvb_frontend.h"
46#include "dvb-pll.h"
47#include "lgdt3302_priv.h"
48#include "lgdt3302.h"
49
50static int debug = 0;
51module_param(debug, int, 0644);
52MODULE_PARM_DESC(debug,"Turn on/off lgdt3302 frontend debugging (default:off).");
53#define dprintk(args...) \
54do { \
55if (debug) printk(KERN_DEBUG "lgdt3302: " args); \
56} while (0)
57
58struct lgdt3302_state
59{
60 struct i2c_adapter* i2c;
61 struct dvb_frontend_ops ops;
62
63 /* Configuration settings */
64 const struct lgdt3302_config* config;
65
66 struct dvb_frontend frontend;
67
68 /* Demodulator private data */
69 fe_modulation_t current_modulation;
70
71 /* Tuner private data */
72 u32 current_frequency;
73};
74
75static int i2c_writebytes (struct lgdt3302_state* state,
76 u8 addr, /* demod_address or pll_address */
77 u8 *buf, /* data bytes to send */
78 int len /* number of bytes to send */ )
79{
80 if (addr == state->config->pll_address) {
81 struct i2c_msg msg =
82 { .addr = addr, .flags = 0, .buf = buf, .len = len };
83 int err;
84
85 if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
86 printk(KERN_WARNING "lgdt3302: %s error (addr %02x <- %02x, err == %i)\n", __FUNCTION__, addr, buf[0], err);
87 return -EREMOTEIO;
88 }
89 } else {
90 u8 tmp[] = { buf[0], buf[1] };
91 struct i2c_msg msg =
92 { .addr = addr, .flags = 0, .buf = tmp, .len = 2 };
93 int err;
94 int i;
95
96 for (i=1; i<len; i++) {
97 tmp[1] = buf[i];
98 if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
99 printk(KERN_WARNING "lgdt3302: %s error (addr %02x <- %02x, err == %i)\n", __FUNCTION__, addr, buf[0], err);
100 return -EREMOTEIO;
101 }
102 tmp[0]++;
103 }
104 }
105 return 0;
106}
107static int i2c_readbytes (struct lgdt3302_state* state,
108 u8 addr, /* demod_address or pll_address */
109 u8 *buf, /* holds data bytes read */
110 int len /* number of bytes to read */ )
111{
112 struct i2c_msg msg =
113 { .addr = addr, .flags = I2C_M_RD, .buf = buf, .len = len };
114 int err;
115
116 if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
117 printk(KERN_WARNING "lgdt3302: %s error (addr %02x, err == %i)\n", __FUNCTION__, addr, err);
118 return -EREMOTEIO;
119 }
120 return 0;
121}
122
123/*
124 * This routine writes the register (reg) to the demod bus
125 * then reads the data returned for (len) bytes.
126 */
127
128static u8 i2c_selectreadbytes (struct lgdt3302_state* state,
129 enum I2C_REG reg, u8* buf, int len)
130{
131 u8 wr [] = { reg };
132 struct i2c_msg msg [] = {
133 { .addr = state->config->demod_address,
134 .flags = 0, .buf = wr, .len = 1 },
135 { .addr = state->config->demod_address,
136 .flags = I2C_M_RD, .buf = buf, .len = len },
137 };
138 int ret;
139 ret = i2c_transfer(state->i2c, msg, 2);
140 if (ret != 2) {
141 printk(KERN_WARNING "lgdt3302: %s: addr 0x%02x select 0x%02x error (ret == %i)\n", __FUNCTION__, state->config->demod_address, reg, ret);
142 } else {
143 ret = 0;
144 }
145 return ret;
146}
147
148/* Software reset */
149int lgdt3302_SwReset(struct lgdt3302_state* state)
150{
151 u8 ret;
152 u8 reset[] = {
153 IRQ_MASK,
154 0x00 /* bit 6 is active low software reset
155 * bits 5-0 are 1 to mask interrupts */
156 };
157
158 ret = i2c_writebytes(state,
159 state->config->demod_address,
160 reset, sizeof(reset));
161 if (ret == 0) {
162 /* spec says reset takes 100 ns why wait */
163 /* mdelay(100); */ /* keep low for 100mS */
164 reset[1] = 0x7f; /* force reset high (inactive)
165 * and unmask interrupts */
166 ret = i2c_writebytes(state,
167 state->config->demod_address,
168 reset, sizeof(reset));
169 }
170 /* Spec does not indicate a need for this either */
171 /*mdelay(5); */ /* wait 5 msec before doing more */
172 return ret;
173}
174
175static int lgdt3302_init(struct dvb_frontend* fe)
176{
177 /* Hardware reset is done using gpio[0] of cx23880x chip.
178 * I'd like to do it here, but don't know how to find chip address.
179 * cx88-cards.c arranges for the reset bit to be inactive (high).
180 * Maybe there needs to be a callable function in cx88-core or
181 * the caller of this function needs to do it. */
182
183 dprintk("%s entered\n", __FUNCTION__);
184 return lgdt3302_SwReset((struct lgdt3302_state*) fe->demodulator_priv);
185}
186
187static int lgdt3302_read_ber(struct dvb_frontend* fe, u32* ber)
188{
189 *ber = 0; /* Dummy out for now */
190 return 0;
191}
192
193static int lgdt3302_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
194{
195 struct lgdt3302_state* state = (struct lgdt3302_state*) fe->demodulator_priv;
196 u8 buf[2];
197
198 i2c_selectreadbytes(state, PACKET_ERR_COUNTER1, buf, sizeof(buf));
199
200 *ucblocks = (buf[0] << 8) | buf[1];
201 return 0;
202}
203
204static int lgdt3302_set_parameters(struct dvb_frontend* fe,
205 struct dvb_frontend_parameters *param)
206{
207 u8 buf[4];
208 struct lgdt3302_state* state =
209 (struct lgdt3302_state*) fe->demodulator_priv;
210
211#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10)
212
213 /* Use 50MHz parameter values from spec sheet since xtal is 50 */
214 static u8 top_ctrl_cfg[] = { TOP_CONTROL, 0x03 };
215 static u8 vsb_freq_cfg[] = { VSB_CARRIER_FREQ0, 0x00, 0x87, 0x8e, 0x01 };
216 static u8 demux_ctrl_cfg[] = { DEMUX_CONTROL, 0xfb };
217 static u8 agc_rf_cfg[] = { AGC_RF_BANDWIDTH0, 0x40, 0x93, 0x00 };
218 static u8 agc_ctrl_cfg[] = { AGC_FUNC_CTRL2, 0xc6, 0x40 };
219 static u8 agc_delay_cfg[] = { AGC_DELAY0, 0x00, 0x00, 0x00 };
220 static u8 agc_loop_cfg[] = { AGC_LOOP_BANDWIDTH0, 0x08, 0x9a };
221
222 /* Change only if we are actually changing the modulation */
223 if (state->current_modulation != param->u.vsb.modulation) {
224 switch(param->u.vsb.modulation) {
225 case VSB_8:
226 dprintk("%s: VSB_8 MODE\n", __FUNCTION__);
227
228 /* Select VSB mode and serial MPEG interface */
229 top_ctrl_cfg[1] = 0x07;
230 break;
231
232 case QAM_64:
233 dprintk("%s: QAM_64 MODE\n", __FUNCTION__);
234
235 /* Select QAM_64 mode and serial MPEG interface */
236 top_ctrl_cfg[1] = 0x04;
237 break;
238
239 case QAM_256:
240 dprintk("%s: QAM_256 MODE\n", __FUNCTION__);
241
242 /* Select QAM_256 mode and serial MPEG interface */
243 top_ctrl_cfg[1] = 0x05;
244 break;
245 default:
246 printk(KERN_WARNING "lgdt3302: %s: Modulation type(%d) UNSUPPORTED\n", __FUNCTION__, param->u.vsb.modulation);
247 return -1;
248 }
249 /* Initializations common to all modes */
250
251 /* Select the requested mode */
252 i2c_writebytes(state, state->config->demod_address,
253 top_ctrl_cfg, sizeof(top_ctrl_cfg));
254
255 /* Change the value of IFBW[11:0]
256 of AGC IF/RF loop filter bandwidth register */
257 i2c_writebytes(state, state->config->demod_address,
258 agc_rf_cfg, sizeof(agc_rf_cfg));
259
260 /* Change the value of bit 6, 'nINAGCBY' and
261 'NSSEL[1:0] of ACG function control register 2 */
262 /* Change the value of bit 6 'RFFIX'
263 of AGC function control register 3 */
264 i2c_writebytes(state, state->config->demod_address,
265 agc_ctrl_cfg, sizeof(agc_ctrl_cfg));
266
267 /* Change the TPCLK pin polarity
268 data is valid on falling clock */
269 i2c_writebytes(state, state->config->demod_address,
270 demux_ctrl_cfg, sizeof(demux_ctrl_cfg));
271
272 if (param->u.vsb.modulation == VSB_8) {
273 /* Initialization for VSB modes only */
274 /* Change the value of NCOCTFV[25:0]of carrier
275 recovery center frequency register for VSB */
276 i2c_writebytes(state, state->config->demod_address,
277 vsb_freq_cfg, sizeof(vsb_freq_cfg));
278 } else {
279 /* Initialization for QAM modes only */
280 /* Set the value of 'INLVTHD' register 0x2a/0x2c
281 to value from 'IFACC' register 0x39/0x3b -1 */
282 int value;
283 i2c_selectreadbytes(state, AGC_RFIF_ACC0,
284 &agc_delay_cfg[1], 3);
285 value = ((agc_delay_cfg[1] & 0x0f) << 8) | agc_delay_cfg[3];
286 value = value -1;
287 dprintk("%s IFACC -1 = 0x%03x\n", __FUNCTION__, value);
288 agc_delay_cfg[1] = (value >> 8) & 0x0f;
289 agc_delay_cfg[2] = 0x00;
290 agc_delay_cfg[3] = value & 0xff;
291 i2c_writebytes(state, state->config->demod_address,
292 agc_delay_cfg, sizeof(agc_delay_cfg));
293
294 /* Change the value of IAGCBW[15:8]
295 of inner AGC loop filter bandwith */
296 i2c_writebytes(state, state->config->demod_address,
297 agc_loop_cfg, sizeof(agc_loop_cfg));
298 }
299
300 state->config->set_ts_params(fe, 0);
301 lgdt3302_SwReset(state);
302 state->current_modulation = param->u.vsb.modulation;
303 }
304#else
305 printk("lgdt3302: %s: you need a newer kernel for this, sorry\n",__FUNCTION__);
306#endif
307
308 /* Change only if we are actually changing the channel */
309 if (state->current_frequency != param->frequency) {
310 dvb_pll_configure(state->config->pll_desc, buf,
311 param->frequency, 0);
312 dprintk("%s: tuner bytes: 0x%02x 0x%02x "
313 "0x%02x 0x%02x\n", __FUNCTION__, buf[0],buf[1],buf[2],buf[3]);
314 i2c_writebytes(state, state->config->pll_address ,buf, 4);
315
316 /* Check the status of the tuner pll */
317 i2c_readbytes(state, state->config->pll_address, buf, 1);
318 dprintk("%s: tuner status byte = 0x%02x\n", __FUNCTION__, buf[0]);
319
320 lgdt3302_SwReset(state);
321
322 /* Update current frequency */
323 state->current_frequency = param->frequency;
324 }
325 return 0;
326}
327
328static int lgdt3302_get_frontend(struct dvb_frontend* fe,
329 struct dvb_frontend_parameters* param)
330{
331 struct lgdt3302_state *state = fe->demodulator_priv;
332 param->frequency = state->current_frequency;
333 return 0;
334}
335
336static int lgdt3302_read_status(struct dvb_frontend* fe, fe_status_t* status)
337{
338 struct lgdt3302_state* state = (struct lgdt3302_state*) fe->demodulator_priv;
339 u8 buf[3];
340
341 *status = 0; /* Reset status result */
342
343 /* Check the status of the tuner pll */
344 i2c_readbytes(state, state->config->pll_address, buf, 1);
345 dprintk("%s: tuner status byte = 0x%02x\n", __FUNCTION__, buf[0]);
346 if ((buf[0] & 0xc0) != 0x40)
347 return 0; /* Tuner PLL not locked or not powered on */
348
349 /*
350 * You must set the Mask bits to 1 in the IRQ_MASK in order
351 * to see that status bit in the IRQ_STATUS register.
352 * This is done in SwReset();
353 */
354
355 /* signal status */
356 i2c_selectreadbytes(state, TOP_CONTROL, buf, sizeof(buf));
357 dprintk("%s: TOP_CONTROL = 0x%02x, IRO_MASK = 0x%02x, IRQ_STATUS = 0x%02x\n", __FUNCTION__, buf[0], buf[1], buf[2]);
358 if ((buf[2] & 0x30) == 0x10)
359 *status |= FE_HAS_SIGNAL;
360
361 /* sync status */
362 if ((buf[2] & 0x03) == 0x01) {
363 *status |= FE_HAS_SYNC;
364 }
365
366 /* FEC error status */
367 if ((buf[2] & 0x0c) == 0x08) {
368 *status |= FE_HAS_LOCK;
369 *status |= FE_HAS_VITERBI;
370 }
371
372#if 0
373 /* Alternative method to check for a signal */
374 /* AGC status register */
375 i2c_selectreadbytes(state, AGC_STATUS, buf, 1);
376 dprintk("%s: AGC_STATUS = 0x%02x\n", __FUNCTION__, buf[0]);
377 if ((buf[0] & 0x0c) == 0x80) /* Test signal does not exist flag */
378 /* Test AGC lock flag */
379 *status |= FE_HAS_SIGNAL;
380 else
381 return 0;
382
383 /* Carrier Recovery Lock Status Register */
384 i2c_selectreadbytes(state, CARRIER_LOCK, buf, 1);
385 dprintk("%s: CARRIER_LOCK = 0x%02x\n", __FUNCTION__, buf[0]);
386 switch (state->current_modulation) {
387 case QAM_256:
388 case QAM_64:
389 /* Need to undestand why there are 3 lock levels here */
390 if ((buf[0] & 0x07) == 0x07)
391 *status |= FE_HAS_CARRIER;
392 else
393 return 0;
394 break;
395#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10)
396 case VSB_8:
397 if ((buf[0] & 0x80) == 0x80)
398 *status |= FE_HAS_CARRIER;
399 else
400 return 0;
401 break;
402#endif
403 default:
404 printk("KERN_WARNING lgdt3302: %s: Modulation set to unsupported value\n", __FUNCTION__);
405 }
406#endif
407
408 return 0;
409}
410
411static int lgdt3302_read_signal_strength(struct dvb_frontend* fe, u16* strength)
412{
413 /* not directly available. */
414 return 0;
415}
416
417static int lgdt3302_read_snr(struct dvb_frontend* fe, u16* snr)
418{
419#ifdef SNR_IN_DB
420 /*
421 * Spec sheet shows formula for SNR_EQ = 10 log10(25 * 24**2 / noise)
422 * and SNR_PH = 10 log10(25 * 32**2 / noise) for equalizer and phase tracker
423 * respectively. The following tables are built on these formulas.
424 * The usual definition is SNR = 20 log10(signal/noise)
425 * If the specification is wrong the value retuned is 1/2 the actual SNR in db.
426 *
427 * This table is a an ordered list of noise values computed by the
428 * formula from the spec sheet such that the index into the table
429 * starting at 43 or 45 is the SNR value in db. There are duplicate noise
430 * value entries at the beginning because the SNR varies more than
431 * 1 db for a change of 1 digit in noise at very small values of noise.
432 *
433 * Examples from SNR_EQ table:
434 * noise SNR
435 * 0 43
436 * 1 42
437 * 2 39
438 * 3 37
439 * 4 36
440 * 5 35
441 * 6 34
442 * 7 33
443 * 8 33
444 * 9 32
445 * 10 32
446 * 11 31
447 * 12 31
448 * 13 30
449 */
450
451 static const u32 SNR_EQ[] =
452 { 1, 2, 2, 2, 3, 3, 4, 4, 5, 7,
453 9, 11, 13, 17, 21, 26, 33, 41, 52, 65,
454 81, 102, 129, 162, 204, 257, 323, 406, 511, 644,
455 810, 1020, 1284, 1616, 2035, 2561, 3224, 4059, 5110, 6433,
456 8098, 10195, 12835, 16158, 20341, 25608, 32238, 40585, 51094, 64323,
457 80978, 101945, 128341, 161571, 203406, 256073, 0x40000
458 };
459
460 static const u32 SNR_PH[] =
461 { 1, 2, 2, 2, 3, 3, 4, 5, 6, 8,
462 10, 12, 15, 19, 23, 29, 37, 46, 58, 73,
463 91, 115, 144, 182, 229, 288, 362, 456, 574, 722,
464 909, 1144, 1440, 1813, 2282, 2873, 3617, 4553, 5732, 7216,
465 9084, 11436, 14396, 18124, 22817, 28724, 36161, 45524, 57312, 72151,
466 90833, 114351, 143960, 181235, 228161, 0x040000
467 };
468
469 static u8 buf[5];/* read data buffer */
470 static u32 noise; /* noise value */
471 static u32 snr_db; /* index into SNR_EQ[] */
472 struct lgdt3302_state* state = (struct lgdt3302_state*) fe->demodulator_priv;
473
474 /* read both equalizer and pase tracker noise data */
475 i2c_selectreadbytes(state, EQPH_ERR0, buf, sizeof(buf));
476
477 if (state->current_modulation == VSB_8) {
478 /* Equalizer Mean-Square Error Register for VSB */
479 noise = ((buf[0] & 7) << 16) | (buf[1] << 8) | buf[2];
480
481 /*
482 * Look up noise value in table.
483 * A better search algorithm could be used...
484 * watch out there are duplicate entries.
485 */
486 for (snr_db = 0; snr_db < sizeof(SNR_EQ); snr_db++) {
487 if (noise < SNR_EQ[snr_db]) {
488 *snr = 43 - snr_db;
489 break;
490 }
491 }
492 } else {
493 /* Phase Tracker Mean-Square Error Register for QAM */
494 noise = ((buf[0] & 7<<3) << 13) | (buf[3] << 8) | buf[4];
495
496 /* Look up noise value in table. */
497 for (snr_db = 0; snr_db < sizeof(SNR_PH); snr_db++) {
498 if (noise < SNR_PH[snr_db]) {
499 *snr = 45 - snr_db;
500 break;
501 }
502 }
503 }
504#else
505 /* Return the raw noise value */
506 static u8 buf[5];/* read data buffer */
507 static u32 noise; /* noise value */
508 struct lgdt3302_state* state = (struct lgdt3302_state*) fe->demodulator_priv;
509
510 /* read both equalizer and pase tracker noise data */
511 i2c_selectreadbytes(state, EQPH_ERR0, buf, sizeof(buf));
512
513 if (state->current_modulation == VSB_8) {
514 /* Equalizer Mean-Square Error Register for VSB */
515 noise = ((buf[0] & 7) << 16) | (buf[1] << 8) | buf[2];
516 } else {
517 /* Phase Tracker Mean-Square Error Register for QAM */
518 noise = ((buf[0] & 7<<3) << 13) | (buf[3] << 8) | buf[4];
519 }
520
521 /* Small values for noise mean signal is better so invert noise */
522 /* Noise is 19 bit value so discard 3 LSB*/
523 *snr = ~noise>>3;
524#endif
525
526 dprintk("%s: noise = 0x%05x, snr = %idb\n",__FUNCTION__, noise, *snr);
527
528 return 0;
529}
530
531static int lgdt3302_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fe_tune_settings)
532{
533 /* I have no idea about this - it may not be needed */
534 fe_tune_settings->min_delay_ms = 500;
535 fe_tune_settings->step_size = 0;
536 fe_tune_settings->max_drift = 0;
537 return 0;
538}
539
540static void lgdt3302_release(struct dvb_frontend* fe)
541{
542 struct lgdt3302_state* state = (struct lgdt3302_state*) fe->demodulator_priv;
543 kfree(state);
544}
545
546static struct dvb_frontend_ops lgdt3302_ops;
547
548struct dvb_frontend* lgdt3302_attach(const struct lgdt3302_config* config,
549 struct i2c_adapter* i2c)
550{
551 struct lgdt3302_state* state = NULL;
552 u8 buf[1];
553
554 /* Allocate memory for the internal state */
555 state = (struct lgdt3302_state*) kmalloc(sizeof(struct lgdt3302_state), GFP_KERNEL);
556 if (state == NULL)
557 goto error;
558 memset(state,0,sizeof(*state));
559
560 /* Setup the state */
561 state->config = config;
562 state->i2c = i2c;
563 memcpy(&state->ops, &lgdt3302_ops, sizeof(struct dvb_frontend_ops));
564 /* Verify communication with demod chip */
565 if (i2c_selectreadbytes(state, 2, buf, 1))
566 goto error;
567
568 state->current_frequency = -1;
569 state->current_modulation = -1;
570
571 /* Create dvb_frontend */
572 state->frontend.ops = &state->ops;
573 state->frontend.demodulator_priv = state;
574 return &state->frontend;
575
576error:
577 if (state)
578 kfree(state);
579 dprintk("%s: ERROR\n",__FUNCTION__);
580 return NULL;
581}
582
583static struct dvb_frontend_ops lgdt3302_ops = {
584 .info = {
585 .name= "LG Electronics LGDT3302 VSB/QAM Frontend",
586 .type = FE_ATSC,
587 .frequency_min= 54000000,
588 .frequency_max= 858000000,
589 .frequency_stepsize= 62500,
590 /* Symbol rate is for all VSB modes need to check QAM */
591 .symbol_rate_min = 10762000,
592 .symbol_rate_max = 10762000,
593 .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
594 },
595 .init = lgdt3302_init,
596 .set_frontend = lgdt3302_set_parameters,
597 .get_frontend = lgdt3302_get_frontend,
598 .get_tune_settings = lgdt3302_get_tune_settings,
599 .read_status = lgdt3302_read_status,
600 .read_ber = lgdt3302_read_ber,
601 .read_signal_strength = lgdt3302_read_signal_strength,
602 .read_snr = lgdt3302_read_snr,
603 .read_ucblocks = lgdt3302_read_ucblocks,
604 .release = lgdt3302_release,
605};
606
607MODULE_DESCRIPTION("LGDT3302 [DViCO FusionHDTV 3 Gold] (ATSC 8VSB & ITU-T J.83 AnnexB 64/256 QAM) Demodulator Driver");
608MODULE_AUTHOR("Wilson Michaels");
609MODULE_LICENSE("GPL");
610
611EXPORT_SYMBOL(lgdt3302_attach);
612
613/*
614 * Local variables:
615 * c-basic-offset: 8
616 * compile-command: "make DVB=1"
617 * End:
618 */
diff --git a/drivers/media/dvb/frontends/lgdt3302.h b/drivers/media/dvb/frontends/lgdt3302.h
new file mode 100644
index 000000000000..81587a40032b
--- /dev/null
+++ b/drivers/media/dvb/frontends/lgdt3302.h
@@ -0,0 +1,49 @@
1/*
2 * $Id: lgdt3302.h,v 1.2 2005/06/28 23:50:48 mkrufky Exp $
3 *
4 * Support for LGDT3302 (DViCO FustionHDTV 3 Gold) - VSB/QAM
5 *
6 * Copyright (C) 2005 Wilson Michaels <wilsonmichaels@earthlink.net>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 */
23
24#ifndef LGDT3302_H
25#define LGDT3302_H
26
27#include <linux/dvb/frontend.h>
28
29struct lgdt3302_config
30{
31 /* The demodulator's i2c address */
32 u8 demod_address;
33 u8 pll_address;
34 struct dvb_pll_desc *pll_desc;
35
36 /* Need to set device param for start_dma */
37 int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
38};
39
40extern struct dvb_frontend* lgdt3302_attach(const struct lgdt3302_config* config,
41 struct i2c_adapter* i2c);
42
43#endif /* LGDT3302_H */
44
45/*
46 * Local variables:
47 * c-basic-offset: 8
48 * End:
49 */
diff --git a/drivers/media/dvb/frontends/lgdt3302_priv.h b/drivers/media/dvb/frontends/lgdt3302_priv.h
new file mode 100644
index 000000000000..6193fa7a569d
--- /dev/null
+++ b/drivers/media/dvb/frontends/lgdt3302_priv.h
@@ -0,0 +1,72 @@
1/*
2 * $Id: lgdt3302_priv.h,v 1.2 2005/06/28 23:50:48 mkrufky Exp $
3 *
4 * Support for LGDT3302 (DViCO FustionHDTV 3 Gold) - VSB/QAM
5 *
6 * Copyright (C) 2005 Wilson Michaels <wilsonmichaels@earthlink.net>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 */
23
24#ifndef _LGDT3302_PRIV_
25#define _LGDT3302_PRIV_
26
27/* i2c control register addresses */
28enum I2C_REG {
29 TOP_CONTROL= 0x00,
30 IRQ_MASK= 0x01,
31 IRQ_STATUS= 0x02,
32 VSB_CARRIER_FREQ0= 0x16,
33 VSB_CARRIER_FREQ1= 0x17,
34 VSB_CARRIER_FREQ2= 0x18,
35 VSB_CARRIER_FREQ3= 0x19,
36 CARRIER_MSEQAM1= 0x1a,
37 CARRIER_MSEQAM2= 0x1b,
38 CARRIER_LOCK= 0x1c,
39 TIMING_RECOVERY= 0x1d,
40 AGC_DELAY0= 0x2a,
41 AGC_DELAY1= 0x2b,
42 AGC_DELAY2= 0x2c,
43 AGC_RF_BANDWIDTH0= 0x2d,
44 AGC_RF_BANDWIDTH1= 0x2e,
45 AGC_RF_BANDWIDTH2= 0x2f,
46 AGC_LOOP_BANDWIDTH0= 0x30,
47 AGC_LOOP_BANDWIDTH1= 0x31,
48 AGC_FUNC_CTRL1= 0x32,
49 AGC_FUNC_CTRL2= 0x33,
50 AGC_FUNC_CTRL3= 0x34,
51 AGC_RFIF_ACC0= 0x39,
52 AGC_RFIF_ACC1= 0x3a,
53 AGC_RFIF_ACC2= 0x3b,
54 AGC_STATUS= 0x3f,
55 SYNC_STATUS_VSB= 0x43,
56 EQPH_ERR0= 0x47,
57 EQ_ERR1= 0x48,
58 EQ_ERR2= 0x49,
59 PH_ERR1= 0x4a,
60 PH_ERR2= 0x4b,
61 DEMUX_CONTROL= 0x66,
62 PACKET_ERR_COUNTER1= 0x6a,
63 PACKET_ERR_COUNTER2= 0x6b,
64};
65
66#endif /* _LGDT3302_PRIV_ */
67
68/*
69 * Local variables:
70 * c-basic-offset: 8
71 * End:
72 */