blob: e94dee50eecdf96b5ed19774fe9714d028918441 [file] [log] [blame]
Mac Michaelsd8667cb2005-07-07 17:58:29 -07001/*
Michael Krufky6ddcc912005-07-27 11:46:00 -07002 * Support for LGDT3302 & LGDT3303 (DViCO FusionHDTV Gold) - VSB/QAM
Mac Michaelsd8667cb2005-07-07 17:58:29 -07003 *
4 * Copyright (C) 2005 Wilson Michaels <wilsonmichaels@earthlink.net>
5 *
6 * Based on code from Kirk Lapray <kirk_lapray@bigfoot.com>
7 * Copyright (C) 2005
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 */
24
25/*
26 * NOTES ABOUT THIS DRIVER
27 *
Michael Krufky6ddcc912005-07-27 11:46:00 -070028 * This driver supports DViCO FusionHDTV Gold under Linux.
Mac Michaelsd8667cb2005-07-07 17:58:29 -070029 *
30 * TODO:
31 * BER and signal strength always return 0.
Michael Krufky6ddcc912005-07-27 11:46:00 -070032 * Include support for LGDT3303
Mac Michaelsd8667cb2005-07-07 17:58:29 -070033 *
34 */
35
Mac Michaelsd8667cb2005-07-07 17:58:29 -070036#include <linux/kernel.h>
37#include <linux/module.h>
38#include <linux/moduleparam.h>
39#include <linux/init.h>
40#include <linux/delay.h>
41#include <asm/byteorder.h>
42
43#include "dvb_frontend.h"
44#include "dvb-pll.h"
Michael Krufky6ddcc912005-07-27 11:46:00 -070045#include "lgdt330x_priv.h"
46#include "lgdt330x.h"
Mac Michaelsd8667cb2005-07-07 17:58:29 -070047
48static int debug = 0;
49module_param(debug, int, 0644);
Michael Krufky6ddcc912005-07-27 11:46:00 -070050MODULE_PARM_DESC(debug,"Turn on/off lgdt330x frontend debugging (default:off).");
Mac Michaelsd8667cb2005-07-07 17:58:29 -070051#define dprintk(args...) \
52do { \
Michael Krufky6ddcc912005-07-27 11:46:00 -070053if (debug) printk(KERN_DEBUG "lgdt330x: " args); \
Mac Michaelsd8667cb2005-07-07 17:58:29 -070054} while (0)
55
Michael Krufky6ddcc912005-07-27 11:46:00 -070056struct lgdt330x_state
Mac Michaelsd8667cb2005-07-07 17:58:29 -070057{
58 struct i2c_adapter* i2c;
59 struct dvb_frontend_ops ops;
60
61 /* Configuration settings */
Michael Krufky6ddcc912005-07-27 11:46:00 -070062 const struct lgdt330x_config* config;
Mac Michaelsd8667cb2005-07-07 17:58:29 -070063
64 struct dvb_frontend frontend;
65
66 /* Demodulator private data */
67 fe_modulation_t current_modulation;
68
69 /* Tuner private data */
70 u32 current_frequency;
71};
72
Michael Krufky6ddcc912005-07-27 11:46:00 -070073static int i2c_writebytes (struct lgdt330x_state* state,
Mac Michaelsd8667cb2005-07-07 17:58:29 -070074 u8 addr, /* demod_address or pll_address */
75 u8 *buf, /* data bytes to send */
76 int len /* number of bytes to send */ )
77{
Michael Krufkyb6aef072005-07-27 11:45:54 -070078 u8 tmp[] = { buf[0], buf[1] };
79 struct i2c_msg msg =
80 { .addr = addr, .flags = 0, .buf = tmp, .len = 2 };
81 int err;
82 int i;
Mac Michaelsd8667cb2005-07-07 17:58:29 -070083
Michael Krufkyb6aef072005-07-27 11:45:54 -070084 for (i=1; i<len; i++) {
85 tmp[1] = buf[i];
Mac Michaelsd8667cb2005-07-07 17:58:29 -070086 if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
Michael Krufky6ddcc912005-07-27 11:46:00 -070087 printk(KERN_WARNING "lgdt330x: %s error (addr %02x <- %02x, err == %i)\n", __FUNCTION__, addr, buf[0], err);
Michael Krufky58ba0062005-07-12 13:58:37 -070088 if (err < 0)
89 return err;
90 else
91 return -EREMOTEIO;
Mac Michaelsd8667cb2005-07-07 17:58:29 -070092 }
Michael Krufkyb6aef072005-07-27 11:45:54 -070093 tmp[0]++;
Mac Michaelsd8667cb2005-07-07 17:58:29 -070094 }
95 return 0;
96}
Michael Krufkyb6aef072005-07-27 11:45:54 -070097
Michael Krufky723d52e2005-07-27 11:45:56 -070098#if 0
Michael Krufky6ddcc912005-07-27 11:46:00 -070099static int i2c_readbytes (struct lgdt330x_state* state,
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700100 u8 addr, /* demod_address or pll_address */
101 u8 *buf, /* holds data bytes read */
102 int len /* number of bytes to read */ )
103{
104 struct i2c_msg msg =
105 { .addr = addr, .flags = I2C_M_RD, .buf = buf, .len = len };
106 int err;
107
108 if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
Michael Krufky6ddcc912005-07-27 11:46:00 -0700109 printk(KERN_WARNING "lgdt330x: %s error (addr %02x, err == %i)\n", __FUNCTION__, addr, err);
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700110 return -EREMOTEIO;
111 }
112 return 0;
113}
Michael Krufky723d52e2005-07-27 11:45:56 -0700114#endif
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700115
116/*
117 * This routine writes the register (reg) to the demod bus
118 * then reads the data returned for (len) bytes.
119 */
120
Michael Krufky6ddcc912005-07-27 11:46:00 -0700121static u8 i2c_selectreadbytes (struct lgdt330x_state* state,
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700122 enum I2C_REG reg, u8* buf, int len)
123{
124 u8 wr [] = { reg };
125 struct i2c_msg msg [] = {
126 { .addr = state->config->demod_address,
127 .flags = 0, .buf = wr, .len = 1 },
128 { .addr = state->config->demod_address,
129 .flags = I2C_M_RD, .buf = buf, .len = len },
130 };
131 int ret;
132 ret = i2c_transfer(state->i2c, msg, 2);
133 if (ret != 2) {
Michael Krufky6ddcc912005-07-27 11:46:00 -0700134 printk(KERN_WARNING "lgdt330x: %s: addr 0x%02x select 0x%02x error (ret == %i)\n", __FUNCTION__, state->config->demod_address, reg, ret);
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700135 } else {
136 ret = 0;
137 }
138 return ret;
139}
140
141/* Software reset */
Michael Krufky6ddcc912005-07-27 11:46:00 -0700142int lgdt330x_SwReset(struct lgdt330x_state* state)
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700143{
144 u8 ret;
145 u8 reset[] = {
146 IRQ_MASK,
147 0x00 /* bit 6 is active low software reset
148 * bits 5-0 are 1 to mask interrupts */
149 };
150
151 ret = i2c_writebytes(state,
152 state->config->demod_address,
153 reset, sizeof(reset));
154 if (ret == 0) {
155 /* spec says reset takes 100 ns why wait */
156 /* mdelay(100); */ /* keep low for 100mS */
157 reset[1] = 0x7f; /* force reset high (inactive)
158 * and unmask interrupts */
159 ret = i2c_writebytes(state,
160 state->config->demod_address,
161 reset, sizeof(reset));
162 }
163 /* Spec does not indicate a need for this either */
164 /*mdelay(5); */ /* wait 5 msec before doing more */
165 return ret;
166}
167
Michael Krufky6ddcc912005-07-27 11:46:00 -0700168static int lgdt330x_init(struct dvb_frontend* fe)
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700169{
170 /* Hardware reset is done using gpio[0] of cx23880x chip.
171 * I'd like to do it here, but don't know how to find chip address.
172 * cx88-cards.c arranges for the reset bit to be inactive (high).
173 * Maybe there needs to be a callable function in cx88-core or
174 * the caller of this function needs to do it. */
175
176 dprintk("%s entered\n", __FUNCTION__);
Michael Krufky6ddcc912005-07-27 11:46:00 -0700177 return lgdt330x_SwReset((struct lgdt330x_state*) fe->demodulator_priv);
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700178}
179
Michael Krufky6ddcc912005-07-27 11:46:00 -0700180static int lgdt330x_read_ber(struct dvb_frontend* fe, u32* ber)
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700181{
182 *ber = 0; /* Dummy out for now */
183 return 0;
184}
185
Michael Krufky6ddcc912005-07-27 11:46:00 -0700186static int lgdt330x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700187{
Michael Krufky6ddcc912005-07-27 11:46:00 -0700188 struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv;
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700189 u8 buf[2];
190
191 i2c_selectreadbytes(state, PACKET_ERR_COUNTER1, buf, sizeof(buf));
192
193 *ucblocks = (buf[0] << 8) | buf[1];
194 return 0;
195}
196
Michael Krufky6ddcc912005-07-27 11:46:00 -0700197static int lgdt330x_set_parameters(struct dvb_frontend* fe,
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700198 struct dvb_frontend_parameters *param)
199{
Michael Krufky6ddcc912005-07-27 11:46:00 -0700200 struct lgdt330x_state* state =
201 (struct lgdt330x_state*) fe->demodulator_priv;
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700202
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700203 /* Use 50MHz parameter values from spec sheet since xtal is 50 */
204 static u8 top_ctrl_cfg[] = { TOP_CONTROL, 0x03 };
205 static u8 vsb_freq_cfg[] = { VSB_CARRIER_FREQ0, 0x00, 0x87, 0x8e, 0x01 };
206 static u8 demux_ctrl_cfg[] = { DEMUX_CONTROL, 0xfb };
207 static u8 agc_rf_cfg[] = { AGC_RF_BANDWIDTH0, 0x40, 0x93, 0x00 };
208 static u8 agc_ctrl_cfg[] = { AGC_FUNC_CTRL2, 0xc6, 0x40 };
Michael Krufky3952db62005-07-14 00:33:33 -0700209 static u8 agc_delay_cfg[] = { AGC_DELAY0, 0x07, 0x00, 0xfe };
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700210 static u8 agc_loop_cfg[] = { AGC_LOOP_BANDWIDTH0, 0x08, 0x9a };
211
212 /* Change only if we are actually changing the modulation */
213 if (state->current_modulation != param->u.vsb.modulation) {
214 switch(param->u.vsb.modulation) {
215 case VSB_8:
216 dprintk("%s: VSB_8 MODE\n", __FUNCTION__);
217
218 /* Select VSB mode and serial MPEG interface */
219 top_ctrl_cfg[1] = 0x07;
Michael Krufky0ccef6d2005-07-27 11:45:55 -0700220
221 /* Select ANT connector if supported by card */
222 if (state->config->pll_rf_set)
223 state->config->pll_rf_set(fe, 1);
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700224 break;
225
226 case QAM_64:
227 dprintk("%s: QAM_64 MODE\n", __FUNCTION__);
228
229 /* Select QAM_64 mode and serial MPEG interface */
230 top_ctrl_cfg[1] = 0x04;
Michael Krufky0ccef6d2005-07-27 11:45:55 -0700231
232 /* Select CABLE connector if supported by card */
233 if (state->config->pll_rf_set)
234 state->config->pll_rf_set(fe, 0);
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700235 break;
236
237 case QAM_256:
238 dprintk("%s: QAM_256 MODE\n", __FUNCTION__);
239
240 /* Select QAM_256 mode and serial MPEG interface */
241 top_ctrl_cfg[1] = 0x05;
Michael Krufky0ccef6d2005-07-27 11:45:55 -0700242
243 /* Select CABLE connector if supported by card */
244 if (state->config->pll_rf_set)
245 state->config->pll_rf_set(fe, 0);
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700246 break;
247 default:
Michael Krufky6ddcc912005-07-27 11:46:00 -0700248 printk(KERN_WARNING "lgdt330x: %s: Modulation type(%d) UNSUPPORTED\n", __FUNCTION__, param->u.vsb.modulation);
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700249 return -1;
250 }
251 /* Initializations common to all modes */
252
253 /* Select the requested mode */
254 i2c_writebytes(state, state->config->demod_address,
255 top_ctrl_cfg, sizeof(top_ctrl_cfg));
256
257 /* Change the value of IFBW[11:0]
258 of AGC IF/RF loop filter bandwidth register */
259 i2c_writebytes(state, state->config->demod_address,
260 agc_rf_cfg, sizeof(agc_rf_cfg));
261
262 /* Change the value of bit 6, 'nINAGCBY' and
263 'NSSEL[1:0] of ACG function control register 2 */
264 /* Change the value of bit 6 'RFFIX'
265 of AGC function control register 3 */
266 i2c_writebytes(state, state->config->demod_address,
267 agc_ctrl_cfg, sizeof(agc_ctrl_cfg));
268
269 /* Change the TPCLK pin polarity
270 data is valid on falling clock */
271 i2c_writebytes(state, state->config->demod_address,
272 demux_ctrl_cfg, sizeof(demux_ctrl_cfg));
273
Michael Krufky58ba0062005-07-12 13:58:37 -0700274 /* Change the value of NCOCTFV[25:0] of carrier
275 recovery center frequency register */
276 i2c_writebytes(state, state->config->demod_address,
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700277 vsb_freq_cfg, sizeof(vsb_freq_cfg));
Michael Krufky3952db62005-07-14 00:33:33 -0700278
279 /* Set the value of 'INLVTHD' register 0x2a/0x2c to 0x7fe */
Michael Krufky58ba0062005-07-12 13:58:37 -0700280 i2c_writebytes(state, state->config->demod_address,
281 agc_delay_cfg, sizeof(agc_delay_cfg));
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700282
Michael Krufky58ba0062005-07-12 13:58:37 -0700283 /* Change the value of IAGCBW[15:8]
284 of inner AGC loop filter bandwith */
285 i2c_writebytes(state, state->config->demod_address,
286 agc_loop_cfg, sizeof(agc_loop_cfg));
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700287
288 state->config->set_ts_params(fe, 0);
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700289 state->current_modulation = param->u.vsb.modulation;
290 }
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700291
292 /* Change only if we are actually changing the channel */
293 if (state->current_frequency != param->frequency) {
Michael Krufkyb6aef072005-07-27 11:45:54 -0700294 u8 buf[5];
Michael Krufky6ddcc912005-07-27 11:46:00 -0700295 struct i2c_msg msg = { .flags = 0, .buf = &buf[1], .len = 4 };
Michael Krufkyb6aef072005-07-27 11:45:54 -0700296 int err;
297
Michael Krufky6ddcc912005-07-27 11:46:00 -0700298 state->config->pll_set(fe, param, buf);
299 msg.addr = buf[0];
300
Michael Krufkyb6aef072005-07-27 11:45:54 -0700301 dprintk("%s: tuner at 0x%02x bytes: 0x%02x 0x%02x "
302 "0x%02x 0x%02x\n", __FUNCTION__,
303 buf[0],buf[1],buf[2],buf[3],buf[4]);
304 if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
Michael Krufky6ddcc912005-07-27 11:46:00 -0700305 printk(KERN_WARNING "lgdt330x: %s error (addr %02x <- %02x, err = %i)\n", __FUNCTION__, buf[0], buf[1], err);
Michael Krufkyb6aef072005-07-27 11:45:54 -0700306 if (err < 0)
307 return err;
308 else
309 return -EREMOTEIO;
310 }
311#if 0
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700312 /* Check the status of the tuner pll */
Michael Krufkyb6aef072005-07-27 11:45:54 -0700313 i2c_readbytes(state, buf[0], &buf[1], 1);
314 dprintk("%s: tuner status byte = 0x%02x\n", __FUNCTION__, buf[1]);
315#endif
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700316 /* Update current frequency */
317 state->current_frequency = param->frequency;
318 }
Michael Krufky6ddcc912005-07-27 11:46:00 -0700319 lgdt330x_SwReset(state);
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700320 return 0;
321}
322
Michael Krufky6ddcc912005-07-27 11:46:00 -0700323static int lgdt330x_get_frontend(struct dvb_frontend* fe,
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700324 struct dvb_frontend_parameters* param)
325{
Michael Krufky6ddcc912005-07-27 11:46:00 -0700326 struct lgdt330x_state *state = fe->demodulator_priv;
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700327 param->frequency = state->current_frequency;
328 return 0;
329}
330
Michael Krufky6ddcc912005-07-27 11:46:00 -0700331static int lgdt330x_read_status(struct dvb_frontend* fe, fe_status_t* status)
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700332{
Michael Krufky6ddcc912005-07-27 11:46:00 -0700333 struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv;
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700334 u8 buf[3];
335
336 *status = 0; /* Reset status result */
337
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700338 /*
339 * You must set the Mask bits to 1 in the IRQ_MASK in order
340 * to see that status bit in the IRQ_STATUS register.
341 * This is done in SwReset();
342 */
343
Michael Krufky08d80522005-07-07 17:58:43 -0700344 /* AGC status register */
345 i2c_selectreadbytes(state, AGC_STATUS, buf, 1);
346 dprintk("%s: AGC_STATUS = 0x%02x\n", __FUNCTION__, buf[0]);
347 if ((buf[0] & 0x0c) == 0x8){
348 /* Test signal does not exist flag */
349 /* as well as the AGC lock flag. */
350 *status |= FE_HAS_SIGNAL;
351 } else {
352 /* Without a signal all other status bits are meaningless */
353 return 0;
354 }
355
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700356 /* signal status */
357 i2c_selectreadbytes(state, TOP_CONTROL, buf, sizeof(buf));
358 dprintk("%s: TOP_CONTROL = 0x%02x, IRO_MASK = 0x%02x, IRQ_STATUS = 0x%02x\n", __FUNCTION__, buf[0], buf[1], buf[2]);
Michael Krufky08d80522005-07-07 17:58:43 -0700359
360#if 0
361 /* Alternative method to check for a signal */
362 /* using the SNR good/bad interrupts. */
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700363 if ((buf[2] & 0x30) == 0x10)
364 *status |= FE_HAS_SIGNAL;
Michael Krufky08d80522005-07-07 17:58:43 -0700365#endif
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700366
367 /* sync status */
368 if ((buf[2] & 0x03) == 0x01) {
369 *status |= FE_HAS_SYNC;
370 }
371
372 /* FEC error status */
373 if ((buf[2] & 0x0c) == 0x08) {
374 *status |= FE_HAS_LOCK;
375 *status |= FE_HAS_VITERBI;
376 }
377
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700378 /* Carrier Recovery Lock Status Register */
379 i2c_selectreadbytes(state, CARRIER_LOCK, buf, 1);
380 dprintk("%s: CARRIER_LOCK = 0x%02x\n", __FUNCTION__, buf[0]);
381 switch (state->current_modulation) {
382 case QAM_256:
383 case QAM_64:
384 /* Need to undestand why there are 3 lock levels here */
385 if ((buf[0] & 0x07) == 0x07)
386 *status |= FE_HAS_CARRIER;
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700387 break;
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700388 case VSB_8:
389 if ((buf[0] & 0x80) == 0x80)
390 *status |= FE_HAS_CARRIER;
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700391 break;
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700392 default:
Michael Krufky6ddcc912005-07-27 11:46:00 -0700393 printk("KERN_WARNING lgdt330x: %s: Modulation set to unsupported value\n", __FUNCTION__);
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700394 }
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700395
396 return 0;
397}
398
Michael Krufky6ddcc912005-07-27 11:46:00 -0700399static int lgdt330x_read_signal_strength(struct dvb_frontend* fe, u16* strength)
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700400{
401 /* not directly available. */
402 return 0;
403}
404
Michael Krufky6ddcc912005-07-27 11:46:00 -0700405static int lgdt330x_read_snr(struct dvb_frontend* fe, u16* snr)
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700406{
407#ifdef SNR_IN_DB
408 /*
409 * Spec sheet shows formula for SNR_EQ = 10 log10(25 * 24**2 / noise)
410 * and SNR_PH = 10 log10(25 * 32**2 / noise) for equalizer and phase tracker
411 * respectively. The following tables are built on these formulas.
412 * The usual definition is SNR = 20 log10(signal/noise)
413 * If the specification is wrong the value retuned is 1/2 the actual SNR in db.
414 *
415 * This table is a an ordered list of noise values computed by the
416 * formula from the spec sheet such that the index into the table
417 * starting at 43 or 45 is the SNR value in db. There are duplicate noise
418 * value entries at the beginning because the SNR varies more than
419 * 1 db for a change of 1 digit in noise at very small values of noise.
420 *
421 * Examples from SNR_EQ table:
422 * noise SNR
423 * 0 43
424 * 1 42
425 * 2 39
426 * 3 37
427 * 4 36
428 * 5 35
429 * 6 34
430 * 7 33
431 * 8 33
432 * 9 32
433 * 10 32
434 * 11 31
435 * 12 31
436 * 13 30
437 */
438
439 static const u32 SNR_EQ[] =
440 { 1, 2, 2, 2, 3, 3, 4, 4, 5, 7,
441 9, 11, 13, 17, 21, 26, 33, 41, 52, 65,
442 81, 102, 129, 162, 204, 257, 323, 406, 511, 644,
443 810, 1020, 1284, 1616, 2035, 2561, 3224, 4059, 5110, 6433,
444 8098, 10195, 12835, 16158, 20341, 25608, 32238, 40585, 51094, 64323,
445 80978, 101945, 128341, 161571, 203406, 256073, 0x40000
446 };
447
448 static const u32 SNR_PH[] =
449 { 1, 2, 2, 2, 3, 3, 4, 5, 6, 8,
450 10, 12, 15, 19, 23, 29, 37, 46, 58, 73,
451 91, 115, 144, 182, 229, 288, 362, 456, 574, 722,
452 909, 1144, 1440, 1813, 2282, 2873, 3617, 4553, 5732, 7216,
453 9084, 11436, 14396, 18124, 22817, 28724, 36161, 45524, 57312, 72151,
454 90833, 114351, 143960, 181235, 228161, 0x040000
455 };
456
457 static u8 buf[5];/* read data buffer */
458 static u32 noise; /* noise value */
459 static u32 snr_db; /* index into SNR_EQ[] */
Michael Krufky6ddcc912005-07-27 11:46:00 -0700460 struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv;
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700461
462 /* read both equalizer and pase tracker noise data */
463 i2c_selectreadbytes(state, EQPH_ERR0, buf, sizeof(buf));
464
465 if (state->current_modulation == VSB_8) {
466 /* Equalizer Mean-Square Error Register for VSB */
467 noise = ((buf[0] & 7) << 16) | (buf[1] << 8) | buf[2];
468
469 /*
470 * Look up noise value in table.
471 * A better search algorithm could be used...
472 * watch out there are duplicate entries.
473 */
474 for (snr_db = 0; snr_db < sizeof(SNR_EQ); snr_db++) {
475 if (noise < SNR_EQ[snr_db]) {
476 *snr = 43 - snr_db;
477 break;
478 }
479 }
480 } else {
481 /* Phase Tracker Mean-Square Error Register for QAM */
482 noise = ((buf[0] & 7<<3) << 13) | (buf[3] << 8) | buf[4];
483
484 /* Look up noise value in table. */
485 for (snr_db = 0; snr_db < sizeof(SNR_PH); snr_db++) {
486 if (noise < SNR_PH[snr_db]) {
487 *snr = 45 - snr_db;
488 break;
489 }
490 }
491 }
492#else
493 /* Return the raw noise value */
494 static u8 buf[5];/* read data buffer */
495 static u32 noise; /* noise value */
Michael Krufky6ddcc912005-07-27 11:46:00 -0700496 struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv;
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700497
498 /* read both equalizer and pase tracker noise data */
499 i2c_selectreadbytes(state, EQPH_ERR0, buf, sizeof(buf));
500
501 if (state->current_modulation == VSB_8) {
502 /* Equalizer Mean-Square Error Register for VSB */
503 noise = ((buf[0] & 7) << 16) | (buf[1] << 8) | buf[2];
504 } else {
505 /* Phase Tracker Mean-Square Error Register for QAM */
506 noise = ((buf[0] & 7<<3) << 13) | (buf[3] << 8) | buf[4];
507 }
508
509 /* Small values for noise mean signal is better so invert noise */
510 /* Noise is 19 bit value so discard 3 LSB*/
511 *snr = ~noise>>3;
512#endif
513
514 dprintk("%s: noise = 0x%05x, snr = %idb\n",__FUNCTION__, noise, *snr);
515
516 return 0;
517}
518
Michael Krufky6ddcc912005-07-27 11:46:00 -0700519static int lgdt330x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fe_tune_settings)
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700520{
521 /* I have no idea about this - it may not be needed */
522 fe_tune_settings->min_delay_ms = 500;
523 fe_tune_settings->step_size = 0;
524 fe_tune_settings->max_drift = 0;
525 return 0;
526}
527
Michael Krufky6ddcc912005-07-27 11:46:00 -0700528static void lgdt330x_release(struct dvb_frontend* fe)
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700529{
Michael Krufky6ddcc912005-07-27 11:46:00 -0700530 struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv;
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700531 kfree(state);
532}
533
Michael Krufky6ddcc912005-07-27 11:46:00 -0700534static struct dvb_frontend_ops lgdt330x_ops;
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700535
Michael Krufky6ddcc912005-07-27 11:46:00 -0700536struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config,
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700537 struct i2c_adapter* i2c)
538{
Michael Krufky6ddcc912005-07-27 11:46:00 -0700539 struct lgdt330x_state* state = NULL;
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700540 u8 buf[1];
541
542 /* Allocate memory for the internal state */
Michael Krufky6ddcc912005-07-27 11:46:00 -0700543 state = (struct lgdt330x_state*) kmalloc(sizeof(struct lgdt330x_state), GFP_KERNEL);
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700544 if (state == NULL)
545 goto error;
546 memset(state,0,sizeof(*state));
547
548 /* Setup the state */
549 state->config = config;
550 state->i2c = i2c;
Michael Krufky6ddcc912005-07-27 11:46:00 -0700551 memcpy(&state->ops, &lgdt330x_ops, sizeof(struct dvb_frontend_ops));
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700552 /* Verify communication with demod chip */
553 if (i2c_selectreadbytes(state, 2, buf, 1))
554 goto error;
555
556 state->current_frequency = -1;
557 state->current_modulation = -1;
558
559 /* Create dvb_frontend */
560 state->frontend.ops = &state->ops;
561 state->frontend.demodulator_priv = state;
562 return &state->frontend;
563
564error:
565 if (state)
566 kfree(state);
567 dprintk("%s: ERROR\n",__FUNCTION__);
568 return NULL;
569}
570
Michael Krufky6ddcc912005-07-27 11:46:00 -0700571static struct dvb_frontend_ops lgdt330x_ops = {
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700572 .info = {
Michael Krufky6ddcc912005-07-27 11:46:00 -0700573 .name= "LG Electronics lgdt330x VSB/QAM Frontend",
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700574 .type = FE_ATSC,
575 .frequency_min= 54000000,
576 .frequency_max= 858000000,
577 .frequency_stepsize= 62500,
578 /* Symbol rate is for all VSB modes need to check QAM */
579 .symbol_rate_min = 10762000,
580 .symbol_rate_max = 10762000,
581 .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
582 },
Michael Krufky6ddcc912005-07-27 11:46:00 -0700583 .init = lgdt330x_init,
584 .set_frontend = lgdt330x_set_parameters,
585 .get_frontend = lgdt330x_get_frontend,
586 .get_tune_settings = lgdt330x_get_tune_settings,
587 .read_status = lgdt330x_read_status,
588 .read_ber = lgdt330x_read_ber,
589 .read_signal_strength = lgdt330x_read_signal_strength,
590 .read_snr = lgdt330x_read_snr,
591 .read_ucblocks = lgdt330x_read_ucblocks,
592 .release = lgdt330x_release,
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700593};
594
Michael Krufky6ddcc912005-07-27 11:46:00 -0700595MODULE_DESCRIPTION("lgdt330x [DViCO FusionHDTV 3 Gold] (ATSC 8VSB & ITU-T J.83 AnnexB 64/256 QAM) Demodulator Driver");
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700596MODULE_AUTHOR("Wilson Michaels");
597MODULE_LICENSE("GPL");
598
Michael Krufky6ddcc912005-07-27 11:46:00 -0700599EXPORT_SYMBOL(lgdt330x_attach);
Mac Michaelsd8667cb2005-07-07 17:58:29 -0700600
601/*
602 * Local variables:
603 * c-basic-offset: 8
604 * compile-command: "make DVB=1"
605 * End:
606 */