Commit 1963c907b21e140082d081b1c8f8c2154593c7d7
Committed by
Linus Torvalds
1 parent
66aea23ff8
Exists in
master
and in
7 other branches
[PATCH] dvb: lgdt330x frontend: some bug fixes & add lgdt3303 support
- Structural changes within lgdt330x driver, framework now supports both chips... tested OK on lgdt3302 and lgdt3303. - Add LG/TUA6034 dvb_pll_desc for ATSC with LG TDVS-H062F & DViCO FusionHDTV5. - Fixed LGDT330X signal strength: For now, always set it to 0. - Corrected LGDT330X boundary condition error in read_snr: dB calculation. Signed-off-by: Mac Michaels <wmichaels1@earthlink.net> Signed-off-by: Michael Krufky <mkrufky@m1k.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Showing 6 changed files with 443 additions and 173 deletions Side-by-side Diff
drivers/media/dvb/frontends/dvb-pll.c
... | ... | @@ -225,6 +225,22 @@ |
225 | 225 | }; |
226 | 226 | EXPORT_SYMBOL(dvb_pll_tua6034); |
227 | 227 | |
228 | +/* Infineon TUA6034 | |
229 | + * used in LG Innotek TDVS-H062F | |
230 | + */ | |
231 | +struct dvb_pll_desc dvb_pll_tdvs_tua6034 = { | |
232 | + .name = "LG/Infineon TUA6034", | |
233 | + .min = 54000000, | |
234 | + .max = 863000000, | |
235 | + .count = 3, | |
236 | + .entries = { | |
237 | + { 160000000, 44000000, 62500, 0xce, 0x01 }, | |
238 | + { 455000000, 44000000, 62500, 0xce, 0x02 }, | |
239 | + { 999999999, 44000000, 62500, 0xce, 0x04 }, | |
240 | + }, | |
241 | +}; | |
242 | +EXPORT_SYMBOL(dvb_pll_tdvs_tua6034); | |
243 | + | |
228 | 244 | /* Philips FMD1216ME |
229 | 245 | * used in Medion Hybrid PCMCIA card and USB Box |
230 | 246 | */ |
drivers/media/dvb/frontends/dvb-pll.h
... | ... | @@ -31,6 +31,7 @@ |
31 | 31 | extern struct dvb_pll_desc dvb_pll_tua6010xs; |
32 | 32 | extern struct dvb_pll_desc dvb_pll_env57h1xd5; |
33 | 33 | extern struct dvb_pll_desc dvb_pll_tua6034; |
34 | +extern struct dvb_pll_desc dvb_pll_tdvs_tua6034; | |
34 | 35 | extern struct dvb_pll_desc dvb_pll_tda665x; |
35 | 36 | extern struct dvb_pll_desc dvb_pll_fmd1216me; |
36 | 37 | extern struct dvb_pll_desc dvb_pll_tded4; |
drivers/media/dvb/frontends/lgdt330x.c
1 | 1 | /* |
2 | - * Support for LGDT3302 & LGDT3303 (DViCO FusionHDTV Gold) - VSB/QAM | |
2 | + * Support for LGDT3302 and LGDT3303 - VSB/QAM | |
3 | 3 | * |
4 | 4 | * Copyright (C) 2005 Wilson Michaels <wilsonmichaels@earthlink.net> |
5 | 5 | * |
6 | - * Based on code from Kirk Lapray <kirk_lapray@bigfoot.com> | |
7 | - * Copyright (C) 2005 | |
8 | - * | |
9 | 6 | * This program is free software; you can redistribute it and/or modify |
10 | 7 | * it under the terms of the GNU General Public License as published by |
11 | 8 | * the Free Software Foundation; either version 2 of the License, or |
12 | 9 | |
... | ... | @@ -25,11 +22,13 @@ |
25 | 22 | /* |
26 | 23 | * NOTES ABOUT THIS DRIVER |
27 | 24 | * |
28 | - * This driver supports DViCO FusionHDTV Gold under Linux. | |
25 | + * This Linux driver supports: | |
26 | + * DViCO FusionHDTV 3 Gold-Q | |
27 | + * DViCO FusionHDTV 3 Gold-T | |
28 | + * DViCO FusionHDTV 5 Gold | |
29 | 29 | * |
30 | 30 | * TODO: |
31 | - * BER and signal strength always return 0. | |
32 | - * Include support for LGDT3303 | |
31 | + * signal strength always returns 0. | |
33 | 32 | * |
34 | 33 | */ |
35 | 34 | |
... | ... | @@ -41,7 +40,6 @@ |
41 | 40 | #include <asm/byteorder.h> |
42 | 41 | |
43 | 42 | #include "dvb_frontend.h" |
44 | -#include "dvb-pll.h" | |
45 | 43 | #include "lgdt330x_priv.h" |
46 | 44 | #include "lgdt330x.h" |
47 | 45 | |
48 | 46 | |
49 | 47 | |
50 | 48 | |
51 | 49 | |
52 | 50 | |
53 | 51 | |
54 | 52 | |
55 | 53 | |
... | ... | @@ -70,55 +68,37 @@ |
70 | 68 | u32 current_frequency; |
71 | 69 | }; |
72 | 70 | |
73 | -static int i2c_writebytes (struct lgdt330x_state* state, | |
74 | - u8 addr, /* demod_address or pll_address */ | |
71 | +static int i2c_write_demod_bytes (struct lgdt330x_state* state, | |
75 | 72 | u8 *buf, /* data bytes to send */ |
76 | 73 | int len /* number of bytes to send */ ) |
77 | 74 | { |
78 | - u8 tmp[] = { buf[0], buf[1] }; | |
79 | 75 | struct i2c_msg msg = |
80 | - { .addr = addr, .flags = 0, .buf = tmp, .len = 2 }; | |
81 | - int err; | |
76 | + { .addr = state->config->demod_address, | |
77 | + .flags = 0, | |
78 | + .buf = buf, | |
79 | + .len = 2 }; | |
82 | 80 | int i; |
81 | + int err; | |
83 | 82 | |
84 | - for (i=1; i<len; i++) { | |
85 | - tmp[1] = buf[i]; | |
83 | + for (i=0; i<len-1; i+=2){ | |
86 | 84 | if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { |
87 | - printk(KERN_WARNING "lgdt330x: %s error (addr %02x <- %02x, err == %i)\n", __FUNCTION__, addr, buf[0], err); | |
85 | + printk(KERN_WARNING "lgdt330x: %s error (addr %02x <- %02x, err = %i)\n", __FUNCTION__, msg.buf[0], msg.buf[1], err); | |
88 | 86 | if (err < 0) |
89 | 87 | return err; |
90 | 88 | else |
91 | 89 | return -EREMOTEIO; |
92 | 90 | } |
93 | - tmp[0]++; | |
91 | + msg.buf += 2; | |
94 | 92 | } |
95 | 93 | return 0; |
96 | 94 | } |
97 | 95 | |
98 | -#if 0 | |
99 | -static int i2c_readbytes (struct lgdt330x_state* state, | |
100 | - 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) { | |
109 | - printk(KERN_WARNING "lgdt330x: %s error (addr %02x, err == %i)\n", __FUNCTION__, addr, err); | |
110 | - return -EREMOTEIO; | |
111 | - } | |
112 | - return 0; | |
113 | -} | |
114 | -#endif | |
115 | - | |
116 | 96 | /* |
117 | 97 | * This routine writes the register (reg) to the demod bus |
118 | 98 | * then reads the data returned for (len) bytes. |
119 | 99 | */ |
120 | 100 | |
121 | -static u8 i2c_selectreadbytes (struct lgdt330x_state* state, | |
101 | +static u8 i2c_read_demod_bytes (struct lgdt330x_state* state, | |
122 | 102 | enum I2C_REG reg, u8* buf, int len) |
123 | 103 | { |
124 | 104 | u8 wr [] = { reg }; |
... | ... | @@ -139,7 +119,7 @@ |
139 | 119 | } |
140 | 120 | |
141 | 121 | /* Software reset */ |
142 | -int lgdt330x_SwReset(struct lgdt330x_state* state) | |
122 | +static int lgdt3302_SwReset(struct lgdt330x_state* state) | |
143 | 123 | { |
144 | 124 | u8 ret; |
145 | 125 | u8 reset[] = { |
146 | 126 | |
147 | 127 | |
148 | 128 | |
... | ... | @@ -148,23 +128,83 @@ |
148 | 128 | * bits 5-0 are 1 to mask interrupts */ |
149 | 129 | }; |
150 | 130 | |
151 | - ret = i2c_writebytes(state, | |
152 | - state->config->demod_address, | |
131 | + ret = i2c_write_demod_bytes(state, | |
153 | 132 | reset, sizeof(reset)); |
154 | 133 | 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, | |
134 | + | |
135 | + /* force reset high (inactive) and unmask interrupts */ | |
136 | + reset[1] = 0x7f; | |
137 | + ret = i2c_write_demod_bytes(state, | |
161 | 138 | reset, sizeof(reset)); |
162 | 139 | } |
163 | - /* Spec does not indicate a need for this either */ | |
164 | - /*mdelay(5); */ /* wait 5 msec before doing more */ | |
165 | 140 | return ret; |
166 | 141 | } |
167 | 142 | |
143 | +static int lgdt3303_SwReset(struct lgdt330x_state* state) | |
144 | +{ | |
145 | + u8 ret; | |
146 | + u8 reset[] = { | |
147 | + 0x02, | |
148 | + 0x00 /* bit 0 is active low software reset */ | |
149 | + }; | |
150 | + | |
151 | + ret = i2c_write_demod_bytes(state, | |
152 | + reset, sizeof(reset)); | |
153 | + if (ret == 0) { | |
154 | + | |
155 | + /* force reset high (inactive) */ | |
156 | + reset[1] = 0x01; | |
157 | + ret = i2c_write_demod_bytes(state, | |
158 | + reset, sizeof(reset)); | |
159 | + } | |
160 | + return ret; | |
161 | +} | |
162 | + | |
163 | +static int lgdt330x_SwReset(struct lgdt330x_state* state) | |
164 | +{ | |
165 | + switch (state->config->demod_chip) { | |
166 | + case LGDT3302: | |
167 | + return lgdt3302_SwReset(state); | |
168 | + case LGDT3303: | |
169 | + return lgdt3303_SwReset(state); | |
170 | + default: | |
171 | + return -ENODEV; | |
172 | + } | |
173 | +} | |
174 | + | |
175 | +#ifdef MUTE_TDA9887 | |
176 | +static int i2c_write_ntsc_demod (struct lgdt330x_state* state, u8 buf[2]) | |
177 | +{ | |
178 | + struct i2c_msg msg = | |
179 | + { .addr = 0x43, | |
180 | + .flags = 0, | |
181 | + .buf = buf, | |
182 | + .len = 2 }; | |
183 | + int err; | |
184 | + | |
185 | + if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { | |
186 | + printk(KERN_WARNING "lgdt330x: %s error (addr %02x <- %02x, err = %i)\n", __FUNCTION__, msg.buf[0], msg.buf[1], err); | |
187 | + if (err < 0) | |
188 | + return err; | |
189 | + else | |
190 | + return -EREMOTEIO; | |
191 | + } | |
192 | + return 0; | |
193 | +} | |
194 | + | |
195 | +static void fiddle_with_ntsc_if_demod(struct lgdt330x_state* state) | |
196 | +{ | |
197 | + // Experimental code | |
198 | + u8 buf0[] = {0x00, 0x20}; | |
199 | + u8 buf1[] = {0x01, 0x00}; | |
200 | + u8 buf2[] = {0x02, 0x00}; | |
201 | + | |
202 | + i2c_write_ntsc_demod(state, buf0); | |
203 | + i2c_write_ntsc_demod(state, buf1); | |
204 | + i2c_write_ntsc_demod(state, buf2); | |
205 | +} | |
206 | +#endif | |
207 | + | |
168 | 208 | static int lgdt330x_init(struct dvb_frontend* fe) |
169 | 209 | { |
170 | 210 | /* Hardware reset is done using gpio[0] of cx23880x chip. |
171 | 211 | |
172 | 212 | |
173 | 213 | |
... | ... | @@ -173,22 +213,101 @@ |
173 | 213 | * Maybe there needs to be a callable function in cx88-core or |
174 | 214 | * the caller of this function needs to do it. */ |
175 | 215 | |
176 | - dprintk("%s entered\n", __FUNCTION__); | |
177 | - return lgdt330x_SwReset((struct lgdt330x_state*) fe->demodulator_priv); | |
216 | + /* | |
217 | + * Array of byte pairs <address, value> | |
218 | + * to initialize each different chip | |
219 | + */ | |
220 | + static u8 lgdt3302_init_data[] = { | |
221 | + /* Use 50MHz parameter values from spec sheet since xtal is 50 */ | |
222 | + /* Change the value of NCOCTFV[25:0] of carrier | |
223 | + recovery center frequency register */ | |
224 | + VSB_CARRIER_FREQ0, 0x00, | |
225 | + VSB_CARRIER_FREQ1, 0x87, | |
226 | + VSB_CARRIER_FREQ2, 0x8e, | |
227 | + VSB_CARRIER_FREQ3, 0x01, | |
228 | + /* Change the TPCLK pin polarity | |
229 | + data is valid on falling clock */ | |
230 | + DEMUX_CONTROL, 0xfb, | |
231 | + /* Change the value of IFBW[11:0] of | |
232 | + AGC IF/RF loop filter bandwidth register */ | |
233 | + AGC_RF_BANDWIDTH0, 0x40, | |
234 | + AGC_RF_BANDWIDTH1, 0x93, | |
235 | + AGC_RF_BANDWIDTH2, 0x00, | |
236 | + /* Change the value of bit 6, 'nINAGCBY' and | |
237 | + 'NSSEL[1:0] of ACG function control register 2 */ | |
238 | + AGC_FUNC_CTRL2, 0xc6, | |
239 | + /* Change the value of bit 6 'RFFIX' | |
240 | + of AGC function control register 3 */ | |
241 | + AGC_FUNC_CTRL3, 0x40, | |
242 | + /* Set the value of 'INLVTHD' register 0x2a/0x2c | |
243 | + to 0x7fe */ | |
244 | + AGC_DELAY0, 0x07, | |
245 | + AGC_DELAY2, 0xfe, | |
246 | + /* Change the value of IAGCBW[15:8] | |
247 | + of inner AGC loop filter bandwith */ | |
248 | + AGC_LOOP_BANDWIDTH0, 0x08, | |
249 | + AGC_LOOP_BANDWIDTH1, 0x9a | |
250 | + }; | |
251 | + | |
252 | + static u8 lgdt3303_init_data[] = { | |
253 | + 0x4c, 0x14 | |
254 | + }; | |
255 | + | |
256 | + struct lgdt330x_state* state = fe->demodulator_priv; | |
257 | + char *chip_name; | |
258 | + int err; | |
259 | + | |
260 | + switch (state->config->demod_chip) { | |
261 | + case LGDT3302: | |
262 | + chip_name = "LGDT3302"; | |
263 | + err = i2c_write_demod_bytes(state, lgdt3302_init_data, | |
264 | + sizeof(lgdt3302_init_data)); | |
265 | + break; | |
266 | + case LGDT3303: | |
267 | + chip_name = "LGDT3303"; | |
268 | + err = i2c_write_demod_bytes(state, lgdt3303_init_data, | |
269 | + sizeof(lgdt3303_init_data)); | |
270 | +#ifdef MUTE_TDA9887 | |
271 | + fiddle_with_ntsc_if_demod(state); | |
272 | +#endif | |
273 | + break; | |
274 | + default: | |
275 | + chip_name = "undefined"; | |
276 | + printk (KERN_WARNING "Only LGDT3302 and LGDT3303 are supported chips.\n"); | |
277 | + err = -ENODEV; | |
278 | + } | |
279 | + dprintk("%s entered as %s\n", __FUNCTION__, chip_name); | |
280 | + if (err < 0) | |
281 | + return err; | |
282 | + return lgdt330x_SwReset(state); | |
178 | 283 | } |
179 | 284 | |
180 | 285 | static int lgdt330x_read_ber(struct dvb_frontend* fe, u32* ber) |
181 | 286 | { |
182 | - *ber = 0; /* Dummy out for now */ | |
287 | + *ber = 0; /* Not supplied by the demod chips */ | |
183 | 288 | return 0; |
184 | 289 | } |
185 | 290 | |
186 | 291 | static int lgdt330x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) |
187 | 292 | { |
188 | - struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv; | |
293 | + struct lgdt330x_state* state = fe->demodulator_priv; | |
294 | + int err; | |
189 | 295 | u8 buf[2]; |
190 | 296 | |
191 | - i2c_selectreadbytes(state, PACKET_ERR_COUNTER1, buf, sizeof(buf)); | |
297 | + switch (state->config->demod_chip) { | |
298 | + case LGDT3302: | |
299 | + err = i2c_read_demod_bytes(state, LGDT3302_PACKET_ERR_COUNTER1, | |
300 | + buf, sizeof(buf)); | |
301 | + break; | |
302 | + case LGDT3303: | |
303 | + err = i2c_read_demod_bytes(state, LGDT3303_PACKET_ERR_COUNTER1, | |
304 | + buf, sizeof(buf)); | |
305 | + break; | |
306 | + default: | |
307 | + printk(KERN_WARNING | |
308 | + "Only LGDT3302 and LGDT3303 are supported chips.\n"); | |
309 | + err = -ENODEV; | |
310 | + } | |
192 | 311 | |
193 | 312 | *ucblocks = (buf[0] << 8) | buf[1]; |
194 | 313 | return 0; |
195 | 314 | |
196 | 315 | |
197 | 316 | |
198 | 317 | |
199 | 318 | |
200 | 319 | |
201 | 320 | |
202 | 321 | |
203 | 322 | |
204 | 323 | |
205 | 324 | |
206 | 325 | |
... | ... | @@ -197,123 +316,113 @@ |
197 | 316 | static int lgdt330x_set_parameters(struct dvb_frontend* fe, |
198 | 317 | struct dvb_frontend_parameters *param) |
199 | 318 | { |
200 | - struct lgdt330x_state* state = | |
201 | - (struct lgdt330x_state*) fe->demodulator_priv; | |
319 | + /* | |
320 | + * Array of byte pairs <address, value> | |
321 | + * to initialize 8VSB for lgdt3303 chip 50 MHz IF | |
322 | + */ | |
323 | + static u8 lgdt3303_8vsb_44_data[] = { | |
324 | + 0x04, 0x00, | |
325 | + 0x0d, 0x40, | |
326 | + 0x0e, 0x87, | |
327 | + 0x0f, 0x8e, | |
328 | + 0x10, 0x01, | |
329 | + 0x47, 0x8b }; | |
202 | 330 | |
203 | - /* Use 50MHz parameter values from spec sheet since xtal is 50 */ | |
331 | + /* | |
332 | + * Array of byte pairs <address, value> | |
333 | + * to initialize QAM for lgdt3303 chip | |
334 | + */ | |
335 | + static u8 lgdt3303_qam_data[] = { | |
336 | + 0x04, 0x00, | |
337 | + 0x0d, 0x00, | |
338 | + 0x0e, 0x00, | |
339 | + 0x0f, 0x00, | |
340 | + 0x10, 0x00, | |
341 | + 0x51, 0x63, | |
342 | + 0x47, 0x66, | |
343 | + 0x48, 0x66, | |
344 | + 0x4d, 0x1a, | |
345 | + 0x49, 0x08, | |
346 | + 0x4a, 0x9b }; | |
347 | + | |
348 | + struct lgdt330x_state* state = fe->demodulator_priv; | |
349 | + | |
204 | 350 | 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 }; | |
209 | - static u8 agc_delay_cfg[] = { AGC_DELAY0, 0x07, 0x00, 0xfe }; | |
210 | - static u8 agc_loop_cfg[] = { AGC_LOOP_BANDWIDTH0, 0x08, 0x9a }; | |
211 | 351 | |
352 | + int err; | |
212 | 353 | /* Change only if we are actually changing the modulation */ |
213 | 354 | if (state->current_modulation != param->u.vsb.modulation) { |
214 | 355 | switch(param->u.vsb.modulation) { |
215 | 356 | case VSB_8: |
216 | 357 | dprintk("%s: VSB_8 MODE\n", __FUNCTION__); |
217 | 358 | |
218 | - /* Select VSB mode and serial MPEG interface */ | |
219 | - top_ctrl_cfg[1] = 0x07; | |
359 | + /* Select VSB mode */ | |
360 | + top_ctrl_cfg[1] = 0x03; | |
220 | 361 | |
221 | 362 | /* Select ANT connector if supported by card */ |
222 | 363 | if (state->config->pll_rf_set) |
223 | 364 | state->config->pll_rf_set(fe, 1); |
365 | + | |
366 | + if (state->config->demod_chip == LGDT3303) { | |
367 | + err = i2c_write_demod_bytes(state, lgdt3303_8vsb_44_data, | |
368 | + sizeof(lgdt3303_8vsb_44_data)); | |
369 | + } | |
224 | 370 | break; |
225 | 371 | |
226 | 372 | case QAM_64: |
227 | 373 | dprintk("%s: QAM_64 MODE\n", __FUNCTION__); |
228 | 374 | |
229 | - /* Select QAM_64 mode and serial MPEG interface */ | |
230 | - top_ctrl_cfg[1] = 0x04; | |
375 | + /* Select QAM_64 mode */ | |
376 | + top_ctrl_cfg[1] = 0x00; | |
231 | 377 | |
232 | 378 | /* Select CABLE connector if supported by card */ |
233 | 379 | if (state->config->pll_rf_set) |
234 | 380 | state->config->pll_rf_set(fe, 0); |
381 | + | |
382 | + if (state->config->demod_chip == LGDT3303) { | |
383 | + err = i2c_write_demod_bytes(state, lgdt3303_qam_data, | |
384 | + sizeof(lgdt3303_qam_data)); | |
385 | + } | |
235 | 386 | break; |
236 | 387 | |
237 | 388 | case QAM_256: |
238 | 389 | dprintk("%s: QAM_256 MODE\n", __FUNCTION__); |
239 | 390 | |
240 | - /* Select QAM_256 mode and serial MPEG interface */ | |
241 | - top_ctrl_cfg[1] = 0x05; | |
391 | + /* Select QAM_256 mode */ | |
392 | + top_ctrl_cfg[1] = 0x01; | |
242 | 393 | |
243 | 394 | /* Select CABLE connector if supported by card */ |
244 | 395 | if (state->config->pll_rf_set) |
245 | 396 | state->config->pll_rf_set(fe, 0); |
397 | + | |
398 | + if (state->config->demod_chip == LGDT3303) { | |
399 | + err = i2c_write_demod_bytes(state, lgdt3303_qam_data, | |
400 | + sizeof(lgdt3303_qam_data)); | |
401 | + } | |
246 | 402 | break; |
247 | 403 | default: |
248 | 404 | printk(KERN_WARNING "lgdt330x: %s: Modulation type(%d) UNSUPPORTED\n", __FUNCTION__, param->u.vsb.modulation); |
249 | 405 | return -1; |
250 | 406 | } |
251 | - /* Initializations common to all modes */ | |
407 | + /* | |
408 | + * select serial or parallel MPEG harware interface | |
409 | + * Serial: 0x04 for LGDT3302 or 0x40 for LGDT3303 | |
410 | + * Parallel: 0x00 | |
411 | + */ | |
412 | + top_ctrl_cfg[1] |= state->config->serial_mpeg; | |
252 | 413 | |
253 | 414 | /* 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 | - | |
274 | - /* Change the value of NCOCTFV[25:0] of carrier | |
275 | - recovery center frequency register */ | |
276 | - i2c_writebytes(state, state->config->demod_address, | |
277 | - vsb_freq_cfg, sizeof(vsb_freq_cfg)); | |
278 | - | |
279 | - /* Set the value of 'INLVTHD' register 0x2a/0x2c to 0x7fe */ | |
280 | - i2c_writebytes(state, state->config->demod_address, | |
281 | - agc_delay_cfg, sizeof(agc_delay_cfg)); | |
282 | - | |
283 | - /* 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)); | |
287 | - | |
415 | + i2c_write_demod_bytes(state, top_ctrl_cfg, | |
416 | + sizeof(top_ctrl_cfg)); | |
288 | 417 | state->config->set_ts_params(fe, 0); |
289 | 418 | state->current_modulation = param->u.vsb.modulation; |
290 | 419 | } |
291 | 420 | |
292 | 421 | /* Change only if we are actually changing the channel */ |
293 | 422 | if (state->current_frequency != param->frequency) { |
294 | - u8 buf[5]; | |
295 | - struct i2c_msg msg = { .flags = 0, .buf = &buf[1], .len = 4 }; | |
296 | - int err; | |
297 | - | |
298 | - state->config->pll_set(fe, param, buf); | |
299 | - msg.addr = buf[0]; | |
300 | - | |
301 | - 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) { | |
305 | - printk(KERN_WARNING "lgdt330x: %s error (addr %02x <- %02x, err = %i)\n", __FUNCTION__, buf[0], buf[1], err); | |
306 | - if (err < 0) | |
307 | - return err; | |
308 | - else | |
309 | - return -EREMOTEIO; | |
310 | - } | |
311 | -#if 0 | |
312 | - /* Check the status of the tuner pll */ | |
313 | - i2c_readbytes(state, buf[0], &buf[1], 1); | |
314 | - dprintk("%s: tuner status byte = 0x%02x\n", __FUNCTION__, buf[1]); | |
315 | -#endif | |
316 | - /* Update current frequency */ | |
423 | + /* Tune to the new frequency */ | |
424 | + state->config->pll_set(fe, param); | |
425 | + /* Keep track of the new frequency */ | |
317 | 426 | state->current_frequency = param->frequency; |
318 | 427 | } |
319 | 428 | lgdt330x_SwReset(state); |
320 | 429 | |
321 | 430 | |
322 | 431 | |
... | ... | @@ -328,21 +437,15 @@ |
328 | 437 | return 0; |
329 | 438 | } |
330 | 439 | |
331 | -static int lgdt330x_read_status(struct dvb_frontend* fe, fe_status_t* status) | |
440 | +static int lgdt3302_read_status(struct dvb_frontend* fe, fe_status_t* status) | |
332 | 441 | { |
333 | - struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv; | |
442 | + struct lgdt330x_state* state = fe->demodulator_priv; | |
334 | 443 | u8 buf[3]; |
335 | 444 | |
336 | 445 | *status = 0; /* Reset status result */ |
337 | 446 | |
338 | - /* | |
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 | - | |
344 | 447 | /* AGC status register */ |
345 | - i2c_selectreadbytes(state, AGC_STATUS, buf, 1); | |
448 | + i2c_read_demod_bytes(state, AGC_STATUS, buf, 1); | |
346 | 449 | dprintk("%s: AGC_STATUS = 0x%02x\n", __FUNCTION__, buf[0]); |
347 | 450 | if ((buf[0] & 0x0c) == 0x8){ |
348 | 451 | /* Test signal does not exist flag */ |
349 | 452 | |
350 | 453 | |
... | ... | @@ -353,16 +456,15 @@ |
353 | 456 | return 0; |
354 | 457 | } |
355 | 458 | |
459 | + /* | |
460 | + * You must set the Mask bits to 1 in the IRQ_MASK in order | |
461 | + * to see that status bit in the IRQ_STATUS register. | |
462 | + * This is done in SwReset(); | |
463 | + */ | |
356 | 464 | /* signal status */ |
357 | - i2c_selectreadbytes(state, TOP_CONTROL, buf, sizeof(buf)); | |
465 | + i2c_read_demod_bytes(state, TOP_CONTROL, buf, sizeof(buf)); | |
358 | 466 | dprintk("%s: TOP_CONTROL = 0x%02x, IRO_MASK = 0x%02x, IRQ_STATUS = 0x%02x\n", __FUNCTION__, buf[0], buf[1], buf[2]); |
359 | 467 | |
360 | -#if 0 | |
361 | - /* Alternative method to check for a signal */ | |
362 | - /* using the SNR good/bad interrupts. */ | |
363 | - if ((buf[2] & 0x30) == 0x10) | |
364 | - *status |= FE_HAS_SIGNAL; | |
365 | -#endif | |
366 | 468 | |
367 | 469 | /* sync status */ |
368 | 470 | if ((buf[2] & 0x03) == 0x01) { |
... | ... | @@ -376,7 +478,7 @@ |
376 | 478 | } |
377 | 479 | |
378 | 480 | /* Carrier Recovery Lock Status Register */ |
379 | - i2c_selectreadbytes(state, CARRIER_LOCK, buf, 1); | |
481 | + i2c_read_demod_bytes(state, CARRIER_LOCK, buf, 1); | |
380 | 482 | dprintk("%s: CARRIER_LOCK = 0x%02x\n", __FUNCTION__, buf[0]); |
381 | 483 | switch (state->current_modulation) { |
382 | 484 | case QAM_256: |
383 | 485 | |
384 | 486 | |
... | ... | @@ -396,13 +498,75 @@ |
396 | 498 | return 0; |
397 | 499 | } |
398 | 500 | |
501 | +static int lgdt3303_read_status(struct dvb_frontend* fe, fe_status_t* status) | |
502 | +{ | |
503 | + struct lgdt330x_state* state = fe->demodulator_priv; | |
504 | + int err; | |
505 | + u8 buf[3]; | |
506 | + | |
507 | + *status = 0; /* Reset status result */ | |
508 | + | |
509 | + /* lgdt3303 AGC status register */ | |
510 | + err = i2c_read_demod_bytes(state, 0x58, buf, 1); | |
511 | + if (err < 0) | |
512 | + return err; | |
513 | + | |
514 | + dprintk("%s: AGC_STATUS = 0x%02x\n", __FUNCTION__, buf[0]); | |
515 | + if ((buf[0] & 0x21) == 0x01){ | |
516 | + /* Test input signal does not exist flag */ | |
517 | + /* as well as the AGC lock flag. */ | |
518 | + *status |= FE_HAS_SIGNAL; | |
519 | + } else { | |
520 | + /* Without a signal all other status bits are meaningless */ | |
521 | + return 0; | |
522 | + } | |
523 | + | |
524 | + /* Carrier Recovery Lock Status Register */ | |
525 | + i2c_read_demod_bytes(state, CARRIER_LOCK, buf, 1); | |
526 | + dprintk("%s: CARRIER_LOCK = 0x%02x\n", __FUNCTION__, buf[0]); | |
527 | + switch (state->current_modulation) { | |
528 | + case QAM_256: | |
529 | + case QAM_64: | |
530 | + /* Need to undestand why there are 3 lock levels here */ | |
531 | + if ((buf[0] & 0x07) == 0x07) | |
532 | + *status |= FE_HAS_CARRIER; | |
533 | + else | |
534 | + break; | |
535 | + i2c_read_demod_bytes(state, 0x8a, buf, 1); | |
536 | + if ((buf[0] & 0x04) == 0x04) | |
537 | + *status |= FE_HAS_SYNC; | |
538 | + if ((buf[0] & 0x01) == 0x01) | |
539 | + *status |= FE_HAS_LOCK; | |
540 | + if ((buf[0] & 0x08) == 0x08) | |
541 | + *status |= FE_HAS_VITERBI; | |
542 | + break; | |
543 | + case VSB_8: | |
544 | + if ((buf[0] & 0x80) == 0x80) | |
545 | + *status |= FE_HAS_CARRIER; | |
546 | + else | |
547 | + break; | |
548 | + i2c_read_demod_bytes(state, 0x38, buf, 1); | |
549 | + if ((buf[0] & 0x02) == 0x00) | |
550 | + *status |= FE_HAS_SYNC; | |
551 | + if ((buf[0] & 0x01) == 0x01) { | |
552 | + *status |= FE_HAS_LOCK; | |
553 | + *status |= FE_HAS_VITERBI; | |
554 | + } | |
555 | + break; | |
556 | + default: | |
557 | + printk("KERN_WARNING lgdt330x: %s: Modulation set to unsupported value\n", __FUNCTION__); | |
558 | + } | |
559 | + return 0; | |
560 | +} | |
561 | + | |
399 | 562 | static int lgdt330x_read_signal_strength(struct dvb_frontend* fe, u16* strength) |
400 | 563 | { |
401 | 564 | /* not directly available. */ |
565 | + *strength = 0; | |
402 | 566 | return 0; |
403 | 567 | } |
404 | 568 | |
405 | -static int lgdt330x_read_snr(struct dvb_frontend* fe, u16* snr) | |
569 | +static int lgdt3302_read_snr(struct dvb_frontend* fe, u16* snr) | |
406 | 570 | { |
407 | 571 | #ifdef SNR_IN_DB |
408 | 572 | /* |
... | ... | @@ -451,7 +615,7 @@ |
451 | 615 | 91, 115, 144, 182, 229, 288, 362, 456, 574, 722, |
452 | 616 | 909, 1144, 1440, 1813, 2282, 2873, 3617, 4553, 5732, 7216, |
453 | 617 | 9084, 11436, 14396, 18124, 22817, 28724, 36161, 45524, 57312, 72151, |
454 | - 90833, 114351, 143960, 181235, 228161, 0x040000 | |
618 | + 90833, 114351, 143960, 181235, 228161, 0x080000 | |
455 | 619 | }; |
456 | 620 | |
457 | 621 | static u8 buf[5];/* read data buffer */ |
... | ... | @@ -459,8 +623,8 @@ |
459 | 623 | static u32 snr_db; /* index into SNR_EQ[] */ |
460 | 624 | struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv; |
461 | 625 | |
462 | - /* read both equalizer and pase tracker noise data */ | |
463 | - i2c_selectreadbytes(state, EQPH_ERR0, buf, sizeof(buf)); | |
626 | + /* read both equalizer and phase tracker noise data */ | |
627 | + i2c_read_demod_bytes(state, EQPH_ERR0, buf, sizeof(buf)); | |
464 | 628 | |
465 | 629 | if (state->current_modulation == VSB_8) { |
466 | 630 | /* Equalizer Mean-Square Error Register for VSB */ |
467 | 631 | |
468 | 632 | |
469 | 633 | |
... | ... | @@ -496,19 +660,20 @@ |
496 | 660 | struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv; |
497 | 661 | |
498 | 662 | /* read both equalizer and pase tracker noise data */ |
499 | - i2c_selectreadbytes(state, EQPH_ERR0, buf, sizeof(buf)); | |
663 | + i2c_read_demod_bytes(state, EQPH_ERR0, buf, sizeof(buf)); | |
500 | 664 | |
501 | 665 | 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 */ | |
666 | + /* Phase Tracker Mean-Square Error Register for VSB */ | |
506 | 667 | noise = ((buf[0] & 7<<3) << 13) | (buf[3] << 8) | buf[4]; |
668 | + } else { | |
669 | + | |
670 | + /* Carrier Recovery Mean-Square Error for QAM */ | |
671 | + i2c_read_demod_bytes(state, 0x1a, buf, 2); | |
672 | + noise = ((buf[0] & 3) << 8) | buf[1]; | |
507 | 673 | } |
508 | 674 | |
509 | 675 | /* 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; | |
676 | + *snr = ~noise; | |
512 | 677 | #endif |
513 | 678 | |
514 | 679 | dprintk("%s: noise = 0x%05x, snr = %idb\n",__FUNCTION__, noise, *snr); |
... | ... | @@ -516,6 +681,32 @@ |
516 | 681 | return 0; |
517 | 682 | } |
518 | 683 | |
684 | +static int lgdt3303_read_snr(struct dvb_frontend* fe, u16* snr) | |
685 | +{ | |
686 | + /* Return the raw noise value */ | |
687 | + static u8 buf[5];/* read data buffer */ | |
688 | + static u32 noise; /* noise value */ | |
689 | + struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv; | |
690 | + | |
691 | + if (state->current_modulation == VSB_8) { | |
692 | + | |
693 | + /* Phase Tracker Mean-Square Error Register for VSB */ | |
694 | + noise = ((buf[0] & 7) << 16) | (buf[3] << 8) | buf[4]; | |
695 | + } else { | |
696 | + | |
697 | + /* Carrier Recovery Mean-Square Error for QAM */ | |
698 | + i2c_read_demod_bytes(state, 0x1a, buf, 2); | |
699 | + noise = (buf[0] << 8) | buf[1]; | |
700 | + } | |
701 | + | |
702 | + /* Small values for noise mean signal is better so invert noise */ | |
703 | + *snr = ~noise; | |
704 | + | |
705 | + dprintk("%s: noise = 0x%05x, snr = %idb\n",__FUNCTION__, noise, *snr); | |
706 | + | |
707 | + return 0; | |
708 | +} | |
709 | + | |
519 | 710 | static int lgdt330x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fe_tune_settings) |
520 | 711 | { |
521 | 712 | /* I have no idea about this - it may not be needed */ |
... | ... | @@ -531,7 +722,8 @@ |
531 | 722 | kfree(state); |
532 | 723 | } |
533 | 724 | |
534 | -static struct dvb_frontend_ops lgdt330x_ops; | |
725 | +static struct dvb_frontend_ops lgdt3302_ops; | |
726 | +static struct dvb_frontend_ops lgdt3303_ops; | |
535 | 727 | |
536 | 728 | struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config, |
537 | 729 | struct i2c_adapter* i2c) |
538 | 730 | |
... | ... | @@ -548,9 +740,19 @@ |
548 | 740 | /* Setup the state */ |
549 | 741 | state->config = config; |
550 | 742 | state->i2c = i2c; |
551 | - memcpy(&state->ops, &lgdt330x_ops, sizeof(struct dvb_frontend_ops)); | |
743 | + switch (config->demod_chip) { | |
744 | + case LGDT3302: | |
745 | + memcpy(&state->ops, &lgdt3302_ops, sizeof(struct dvb_frontend_ops)); | |
746 | + break; | |
747 | + case LGDT3303: | |
748 | + memcpy(&state->ops, &lgdt3303_ops, sizeof(struct dvb_frontend_ops)); | |
749 | + break; | |
750 | + default: | |
751 | + goto error; | |
752 | + } | |
753 | + | |
552 | 754 | /* Verify communication with demod chip */ |
553 | - if (i2c_selectreadbytes(state, 2, buf, 1)) | |
755 | + if (i2c_read_demod_bytes(state, 2, buf, 1)) | |
554 | 756 | goto error; |
555 | 757 | |
556 | 758 | state->current_frequency = -1; |
557 | 759 | |
... | ... | @@ -568,9 +770,9 @@ |
568 | 770 | return NULL; |
569 | 771 | } |
570 | 772 | |
571 | -static struct dvb_frontend_ops lgdt330x_ops = { | |
773 | +static struct dvb_frontend_ops lgdt3302_ops = { | |
572 | 774 | .info = { |
573 | - .name= "LG Electronics lgdt330x VSB/QAM Frontend", | |
775 | + .name= "LG Electronics LGDT3302/LGDT3303 VSB/QAM Frontend", | |
574 | 776 | .type = FE_ATSC, |
575 | 777 | .frequency_min= 54000000, |
576 | 778 | .frequency_max= 858000000, |
577 | 779 | |
578 | 780 | |
... | ... | @@ -584,15 +786,39 @@ |
584 | 786 | .set_frontend = lgdt330x_set_parameters, |
585 | 787 | .get_frontend = lgdt330x_get_frontend, |
586 | 788 | .get_tune_settings = lgdt330x_get_tune_settings, |
587 | - .read_status = lgdt330x_read_status, | |
789 | + .read_status = lgdt3302_read_status, | |
588 | 790 | .read_ber = lgdt330x_read_ber, |
589 | 791 | .read_signal_strength = lgdt330x_read_signal_strength, |
590 | - .read_snr = lgdt330x_read_snr, | |
792 | + .read_snr = lgdt3302_read_snr, | |
591 | 793 | .read_ucblocks = lgdt330x_read_ucblocks, |
592 | 794 | .release = lgdt330x_release, |
593 | 795 | }; |
594 | 796 | |
595 | -MODULE_DESCRIPTION("lgdt330x [DViCO FusionHDTV 3 Gold] (ATSC 8VSB & ITU-T J.83 AnnexB 64/256 QAM) Demodulator Driver"); | |
797 | +static struct dvb_frontend_ops lgdt3303_ops = { | |
798 | + .info = { | |
799 | + .name= "LG Electronics LGDT3303 VSB/QAM Frontend", | |
800 | + .type = FE_ATSC, | |
801 | + .frequency_min= 54000000, | |
802 | + .frequency_max= 858000000, | |
803 | + .frequency_stepsize= 62500, | |
804 | + /* Symbol rate is for all VSB modes need to check QAM */ | |
805 | + .symbol_rate_min = 10762000, | |
806 | + .symbol_rate_max = 10762000, | |
807 | + .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB | |
808 | + }, | |
809 | + .init = lgdt330x_init, | |
810 | + .set_frontend = lgdt330x_set_parameters, | |
811 | + .get_frontend = lgdt330x_get_frontend, | |
812 | + .get_tune_settings = lgdt330x_get_tune_settings, | |
813 | + .read_status = lgdt3303_read_status, | |
814 | + .read_ber = lgdt330x_read_ber, | |
815 | + .read_signal_strength = lgdt330x_read_signal_strength, | |
816 | + .read_snr = lgdt3303_read_snr, | |
817 | + .read_ucblocks = lgdt330x_read_ucblocks, | |
818 | + .release = lgdt330x_release, | |
819 | +}; | |
820 | + | |
821 | +MODULE_DESCRIPTION("LGDT330X (ATSC 8VSB & ITU-T J.83 AnnexB 64/256 QAM) Demodulator Driver"); | |
596 | 822 | MODULE_AUTHOR("Wilson Michaels"); |
597 | 823 | MODULE_LICENSE("GPL"); |
598 | 824 | |
... | ... | @@ -601,7 +827,6 @@ |
601 | 827 | /* |
602 | 828 | * Local variables: |
603 | 829 | * c-basic-offset: 8 |
604 | - * compile-command: "make DVB=1" | |
605 | 830 | * End: |
606 | 831 | */ |
drivers/media/dvb/frontends/lgdt330x.h
1 | 1 | /* |
2 | - * Support for LGDT3302 & LGDT3303 (DViCO FustionHDTV Gold) - VSB/QAM | |
2 | + * Support for LGDT3302 and LGDT3303 - VSB/QAM | |
3 | 3 | * |
4 | 4 | * Copyright (C) 2005 Wilson Michaels <wilsonmichaels@earthlink.net> |
5 | 5 | * |
6 | 6 | |
7 | 7 | |
... | ... | @@ -24,14 +24,26 @@ |
24 | 24 | |
25 | 25 | #include <linux/dvb/frontend.h> |
26 | 26 | |
27 | +typedef enum lg_chip_t { | |
28 | + UNDEFINED, | |
29 | + LGDT3302, | |
30 | + LGDT3303 | |
31 | +}lg_chip_type; | |
32 | + | |
27 | 33 | struct lgdt330x_config |
28 | 34 | { |
29 | 35 | /* The demodulator's i2c address */ |
30 | 36 | u8 demod_address; |
31 | 37 | |
38 | + /* LG demodulator chip LGDT3302 or LGDT3303 */ | |
39 | + lg_chip_type demod_chip; | |
40 | + | |
41 | + /* MPEG hardware interface - 0:parallel 1:serial */ | |
42 | + int serial_mpeg; | |
43 | + | |
32 | 44 | /* PLL interface */ |
33 | 45 | int (*pll_rf_set) (struct dvb_frontend* fe, int index); |
34 | - int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pll_address); | |
46 | + int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); | |
35 | 47 | |
36 | 48 | /* Need to set device param for start_dma */ |
37 | 49 | int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured); |
drivers/media/dvb/frontends/lgdt330x_priv.h
1 | 1 | /* |
2 | - * Support for LGDT3302 & LGDT3303 (DViCO FustionHDTV Gold) - VSB/QAM | |
2 | + * Support for LGDT3302 and LGDT3303 - VSB/QAM | |
3 | 3 | * |
4 | 4 | * Copyright (C) 2005 Wilson Michaels <wilsonmichaels@earthlink.net> |
5 | 5 | * |
... | ... | @@ -57,8 +57,10 @@ |
57 | 57 | PH_ERR1= 0x4a, |
58 | 58 | PH_ERR2= 0x4b, |
59 | 59 | DEMUX_CONTROL= 0x66, |
60 | - PACKET_ERR_COUNTER1= 0x6a, | |
61 | - PACKET_ERR_COUNTER2= 0x6b, | |
60 | + LGDT3302_PACKET_ERR_COUNTER1= 0x6a, | |
61 | + LGDT3302_PACKET_ERR_COUNTER2= 0x6b, | |
62 | + LGDT3303_PACKET_ERR_COUNTER1= 0x8b, | |
63 | + LGDT3303_PACKET_ERR_COUNTER2= 0x8c, | |
62 | 64 | }; |
63 | 65 | |
64 | 66 | #endif /* _LGDT330X_PRIV_ */ |
drivers/media/video/cx88/cx88-dvb.c
1 | 1 | /* |
2 | - * $Id: cx88-dvb.c,v 1.54 2005/07/25 05:13:50 mkrufky Exp $ | |
2 | + * $Id: cx88-dvb.c,v 1.58 2005/08/07 09:24:08 mkrufky Exp $ | |
3 | 3 | * |
4 | 4 | * device driver for Conexant 2388x based TV cards |
5 | 5 | * MPEG Transport Stream (DVB) routines |
6 | 6 | |
7 | 7 | |
... | ... | @@ -208,14 +208,26 @@ |
208 | 208 | |
209 | 209 | #ifdef HAVE_LGDT330X |
210 | 210 | static int lgdt330x_pll_set(struct dvb_frontend* fe, |
211 | - struct dvb_frontend_parameters* params, | |
212 | - u8* pllbuf) | |
211 | + struct dvb_frontend_parameters* params) | |
213 | 212 | { |
214 | 213 | struct cx8802_dev *dev= fe->dvb->priv; |
214 | + u8 buf[4]; | |
215 | + struct i2c_msg msg = | |
216 | + { .addr = dev->core->pll_addr, .flags = 0, .buf = buf, .len = 4 }; | |
217 | + int err; | |
215 | 218 | |
216 | - pllbuf[0] = dev->core->pll_addr; | |
217 | - dvb_pll_configure(dev->core->pll_desc, &pllbuf[1], | |
218 | - params->frequency, 0); | |
219 | + dvb_pll_configure(dev->core->pll_desc, buf, params->frequency, 0); | |
220 | + dprintk(1, "%s: tuner at 0x%02x bytes: 0x%02x 0x%02x 0x%02x 0x%02x\n", | |
221 | + __FUNCTION__, msg.addr, buf[0],buf[1],buf[2],buf[3]); | |
222 | + if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) { | |
223 | + printk(KERN_WARNING "cx88-dvb: %s error " | |
224 | + "(addr %02x <- %02x, err = %i)\n", | |
225 | + __FUNCTION__, buf[0], buf[1], err); | |
226 | + if (err < 0) | |
227 | + return err; | |
228 | + else | |
229 | + return -EREMOTEIO; | |
230 | + } | |
219 | 231 | return 0; |
220 | 232 | } |
221 | 233 | |
... | ... | @@ -244,6 +256,8 @@ |
244 | 256 | |
245 | 257 | static struct lgdt330x_config fusionhdtv_3_gold = { |
246 | 258 | .demod_address = 0x0e, |
259 | + .demod_chip = LGDT3302, | |
260 | + .serial_mpeg = 0x04, /* TPSERIAL for 3302 in TOP_CONTROL */ | |
247 | 261 | .pll_set = lgdt330x_pll_set, |
248 | 262 | .set_ts_params = lgdt330x_set_ts_param, |
249 | 263 | }; |