diff options
author | Yeasah Pell <yeasah@schwide.net> | 2006-04-13 16:24:13 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2006-05-12 18:55:07 -0400 |
commit | 0e4558ab4a89a127e0de36746552da9353e35f10 (patch) | |
tree | 19fe0a9c2c9d9d4f5ed5f4e7b08ddfbf1b466010 /drivers/media | |
parent | dce1dfc2a5736bfc82df5d3fd6396022c7bbbbd8 (diff) |
V4L/DVB (3803): Various correctness fixes to tuning.
*) Sets an additional tuner parameter (demodulator sample gain) that
wasn't being set before.
*) Removes the low symbol rate tuner parameter tweaks in the previous
patch -- it appears those tweaks are not necessary with the demodulator
sample gain set correctly.
*) Cleanup and document the demodulator register initialization sequence.
*) Change set_fec routine to disable FEC auto scan when a specific code
rate is selected.
*) Remove error message when reported FEC is invalid (which happens
sometimes when the card has no signal)
Signed-off-by: Yeasah Pell <yeasah at schwide.net>
Signed-off-by: Andrew de Quincey <adq_dvb@lidskialf.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/dvb/frontends/cx24123.c | 172 |
1 files changed, 108 insertions, 64 deletions
diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c index fa6cdba08d25..2aac17451d75 100644 --- a/drivers/media/dvb/frontends/cx24123.c +++ b/drivers/media/dvb/frontends/cx24123.c | |||
@@ -76,23 +76,23 @@ static struct | |||
76 | .symbolrate_high = 4999999, | 76 | .symbolrate_high = 4999999, |
77 | /* the specs recommend other values for VGA offsets, | 77 | /* the specs recommend other values for VGA offsets, |
78 | but tests show they are wrong */ | 78 | but tests show they are wrong */ |
79 | .VGAprogdata = (2 << 18) | (0x180 << 9) | 0x1e0, | 79 | .VGAprogdata = (1 << 19) | (0x180 << 9) | 0x1e0, |
80 | .VCAprogdata = (4 << 18) | (0x07 << 9) | 0x07, | 80 | .VCAprogdata = (2 << 19) | (0x07 << 9) | 0x07, |
81 | .FILTune = 0x280 /* 0.41 V */ | 81 | .FILTune = 0x27f /* 0.41 V */ |
82 | }, | 82 | }, |
83 | { | 83 | { |
84 | .symbolrate_low = 5000000, | 84 | .symbolrate_low = 5000000, |
85 | .symbolrate_high = 14999999, | 85 | .symbolrate_high = 14999999, |
86 | .VGAprogdata = (2 << 18) | (0x180 << 9) | 0x1e0, | 86 | .VGAprogdata = (1 << 19) | (0x180 << 9) | 0x1e0, |
87 | .VCAprogdata = (4 << 18) | (0x07 << 9) | 0x1f, | 87 | .VCAprogdata = (2 << 19) | (0x07 << 9) | 0x1f, |
88 | .FILTune = 0x317 /* 0.90 V */ | 88 | .FILTune = 0x317 /* 0.90 V */ |
89 | }, | 89 | }, |
90 | { | 90 | { |
91 | .symbolrate_low = 15000000, | 91 | .symbolrate_low = 15000000, |
92 | .symbolrate_high = 45000000, | 92 | .symbolrate_high = 45000000, |
93 | .VGAprogdata = (2 << 18) | (0x100 << 9) | 0x180, | 93 | .VGAprogdata = (1 << 19) | (0x100 << 9) | 0x180, |
94 | .VCAprogdata = (4 << 18) | (0x07 << 9) | 0x3f, | 94 | .VCAprogdata = (2 << 19) | (0x07 << 9) | 0x3f, |
95 | .FILTune = 0x146 /* 2.70 V */ | 95 | .FILTune = 0x145 /* 2.70 V */ |
96 | }, | 96 | }, |
97 | }; | 97 | }; |
98 | 98 | ||
@@ -178,45 +178,44 @@ static struct { | |||
178 | { | 178 | { |
179 | {0x00, 0x03}, /* Reset system */ | 179 | {0x00, 0x03}, /* Reset system */ |
180 | {0x00, 0x00}, /* Clear reset */ | 180 | {0x00, 0x00}, /* Clear reset */ |
181 | {0x03, 0x07}, | 181 | {0x03, 0x07}, /* QPSK, DVB, Auto Acquisition (default) */ |
182 | {0x04, 0x10}, | 182 | {0x04, 0x10}, /* MPEG */ |
183 | {0x05, 0x04}, | 183 | {0x05, 0x04}, /* MPEG */ |
184 | {0x06, 0x31}, | 184 | {0x06, 0x31}, /* MPEG (default) */ |
185 | {0x0d, 0x02}, | 185 | {0x0b, 0x00}, /* Freq search start point (default) */ |
186 | {0x0e, 0x03}, | 186 | {0x0c, 0x00}, /* Demodulator sample gain (default) */ |
187 | {0x0f, 0xfe}, | 187 | {0x0d, 0x02}, /* Frequency search range = Fsymbol / 4 (default) */ |
188 | {0x10, 0x01}, | 188 | {0x0e, 0x03}, /* Default non-inverted, FEC 3/4 (default) */ |
189 | {0x14, 0x01}, | 189 | {0x0f, 0xfe}, /* FEC search mask (all supported codes) */ |
190 | {0x16, 0x00}, | 190 | {0x10, 0x01}, /* Default search inversion, no repeat (default) */ |
191 | {0x17, 0x01}, | 191 | {0x16, 0x00}, /* Enable reading of frequency */ |
192 | {0x1b, 0x05}, | 192 | {0x17, 0x01}, /* Enable EsNO Ready Counter */ |
193 | {0x1c, 0x80}, | 193 | {0x1c, 0x80}, /* Enable error counter */ |
194 | {0x1d, 0x00}, | 194 | {0x20, 0x00}, /* Tuner burst clock rate = 500KHz */ |
195 | {0x1e, 0x00}, | 195 | {0x21, 0x15}, /* Tuner burst mode, word length = 0x15 */ |
196 | {0x20, 0x41}, | 196 | {0x28, 0x00}, /* Enable FILTERV with positive pol., DiSEqC 2.x off */ |
197 | {0x21, 0x15}, | 197 | {0x29, 0x00}, /* DiSEqC LNB_DC off */ |
198 | {0x29, 0x00}, | 198 | {0x2a, 0xb0}, /* DiSEqC Parameters (default) */ |
199 | {0x2a, 0xb0}, | 199 | {0x2b, 0x73}, /* DiSEqC Tone Frequency (default) */ |
200 | {0x2b, 0x73}, | 200 | {0x2c, 0x00}, /* DiSEqC Message (0x2c - 0x31) */ |
201 | {0x2c, 0x00}, | ||
202 | {0x2d, 0x00}, | 201 | {0x2d, 0x00}, |
203 | {0x2e, 0x00}, | 202 | {0x2e, 0x00}, |
204 | {0x2f, 0x00}, | 203 | {0x2f, 0x00}, |
205 | {0x30, 0x00}, | 204 | {0x30, 0x00}, |
206 | {0x31, 0x00}, | 205 | {0x31, 0x00}, |
207 | {0x32, 0x8c}, | 206 | {0x32, 0x8c}, /* DiSEqC Parameters (default) */ |
208 | {0x33, 0x00}, | 207 | {0x33, 0x00}, /* Interrupts off (0x33 - 0x34) */ |
209 | {0x34, 0x00}, | 208 | {0x34, 0x00}, |
210 | {0x35, 0x03}, | 209 | {0x35, 0x03}, /* DiSEqC Tone Amplitude (default) */ |
211 | {0x36, 0x02}, | 210 | {0x36, 0x02}, /* DiSEqC Parameters (default) */ |
212 | {0x37, 0x3a}, | 211 | {0x37, 0x3a}, /* DiSEqC Parameters (default) */ |
213 | {0x3a, 0x00}, /* Enable AGC accumulator */ | 212 | {0x3a, 0x00}, /* Enable AGC accumulator (for signal strength) */ |
214 | {0x44, 0x00}, | 213 | {0x44, 0x00}, /* Constellation (default) */ |
215 | {0x45, 0x00}, | 214 | {0x45, 0x00}, /* Symbol count (default) */ |
216 | {0x46, 0x05}, | 215 | {0x46, 0x0d}, /* Symbol rate estimator on (default) */ |
217 | {0x56, 0x41}, | 216 | {0x56, 0x41}, /* Various (default) */ |
218 | {0x57, 0xff}, | 217 | {0x57, 0xff}, /* Error Counter Window (default) */ |
219 | {0x67, 0x83}, | 218 | {0x67, 0x83}, /* Non-DCII symbol clock */ |
220 | }; | 219 | }; |
221 | 220 | ||
222 | static int cx24123_writereg(struct cx24123_state* state, int reg, int data) | 221 | static int cx24123_writereg(struct cx24123_state* state, int reg, int data) |
@@ -291,20 +290,23 @@ static int cx24123_readlnbreg(struct cx24123_state* state, u8 reg) | |||
291 | 290 | ||
292 | static int cx24123_set_inversion(struct cx24123_state* state, fe_spectral_inversion_t inversion) | 291 | static int cx24123_set_inversion(struct cx24123_state* state, fe_spectral_inversion_t inversion) |
293 | { | 292 | { |
293 | u8 nom_reg = cx24123_readreg(state, 0x0e); | ||
294 | u8 auto_reg = cx24123_readreg(state, 0x10); | ||
295 | |||
294 | switch (inversion) { | 296 | switch (inversion) { |
295 | case INVERSION_OFF: | 297 | case INVERSION_OFF: |
296 | dprintk("%s: inversion off\n",__FUNCTION__); | 298 | dprintk("%s: inversion off\n",__FUNCTION__); |
297 | cx24123_writereg(state, 0x0e, cx24123_readreg(state, 0x0e) & 0x7f); | 299 | cx24123_writereg(state, 0x0e, nom_reg & ~0x80); |
298 | cx24123_writereg(state, 0x10, cx24123_readreg(state, 0x10) | 0x80); | 300 | cx24123_writereg(state, 0x10, auto_reg | 0x80); |
299 | break; | 301 | break; |
300 | case INVERSION_ON: | 302 | case INVERSION_ON: |
301 | dprintk("%s: inversion on\n",__FUNCTION__); | 303 | dprintk("%s: inversion on\n",__FUNCTION__); |
302 | cx24123_writereg(state, 0x0e, cx24123_readreg(state, 0x0e) | 0x80); | 304 | cx24123_writereg(state, 0x0e, nom_reg | 0x80); |
303 | cx24123_writereg(state, 0x10, cx24123_readreg(state, 0x10) | 0x80); | 305 | cx24123_writereg(state, 0x10, auto_reg | 0x80); |
304 | break; | 306 | break; |
305 | case INVERSION_AUTO: | 307 | case INVERSION_AUTO: |
306 | dprintk("%s: inversion auto\n",__FUNCTION__); | 308 | dprintk("%s: inversion auto\n",__FUNCTION__); |
307 | cx24123_writereg(state, 0x10, cx24123_readreg(state, 0x10) & 0x7f); | 309 | cx24123_writereg(state, 0x10, auto_reg & ~0x80); |
308 | break; | 310 | break; |
309 | default: | 311 | default: |
310 | return -EINVAL; | 312 | return -EINVAL; |
@@ -332,35 +334,56 @@ static int cx24123_get_inversion(struct cx24123_state* state, fe_spectral_invers | |||
332 | 334 | ||
333 | static int cx24123_set_fec(struct cx24123_state* state, fe_code_rate_t fec) | 335 | static int cx24123_set_fec(struct cx24123_state* state, fe_code_rate_t fec) |
334 | { | 336 | { |
337 | u8 nom_reg = cx24123_readreg(state, 0x0e) & ~0x07; | ||
338 | |||
335 | if ( (fec < FEC_NONE) || (fec > FEC_AUTO) ) | 339 | if ( (fec < FEC_NONE) || (fec > FEC_AUTO) ) |
336 | fec = FEC_AUTO; | 340 | fec = FEC_AUTO; |
337 | 341 | ||
338 | /* Hardware has 5/11 and 3/5 but are never unused */ | ||
339 | switch (fec) { | 342 | switch (fec) { |
340 | case FEC_NONE: | ||
341 | dprintk("%s: set FEC to none\n",__FUNCTION__); | ||
342 | return cx24123_writereg(state, 0x0f, 0x01); | ||
343 | case FEC_1_2: | 343 | case FEC_1_2: |
344 | dprintk("%s: set FEC to 1/2\n",__FUNCTION__); | 344 | dprintk("%s: set FEC to 1/2\n",__FUNCTION__); |
345 | return cx24123_writereg(state, 0x0f, 0x02); | 345 | cx24123_writereg(state, 0x0e, nom_reg | 0x01); |
346 | cx24123_writereg(state, 0x0f, 0x02); | ||
347 | break; | ||
346 | case FEC_2_3: | 348 | case FEC_2_3: |
347 | dprintk("%s: set FEC to 2/3\n",__FUNCTION__); | 349 | dprintk("%s: set FEC to 2/3\n",__FUNCTION__); |
348 | return cx24123_writereg(state, 0x0f, 0x04); | 350 | cx24123_writereg(state, 0x0e, nom_reg | 0x02); |
351 | cx24123_writereg(state, 0x0f, 0x04); | ||
352 | break; | ||
349 | case FEC_3_4: | 353 | case FEC_3_4: |
350 | dprintk("%s: set FEC to 3/4\n",__FUNCTION__); | 354 | dprintk("%s: set FEC to 3/4\n",__FUNCTION__); |
351 | return cx24123_writereg(state, 0x0f, 0x08); | 355 | cx24123_writereg(state, 0x0e, nom_reg | 0x03); |
352 | case FEC_5_6: | 356 | cx24123_writereg(state, 0x0f, 0x08); |
357 | break; | ||
358 | case FEC_4_5: | ||
353 | dprintk("%s: set FEC to 4/5\n",__FUNCTION__); | 359 | dprintk("%s: set FEC to 4/5\n",__FUNCTION__); |
354 | return cx24123_writereg(state, 0x0f, 0x20); | 360 | cx24123_writereg(state, 0x0e, nom_reg | 0x04); |
355 | case FEC_7_8: | 361 | cx24123_writereg(state, 0x0f, 0x10); |
362 | break; | ||
363 | case FEC_5_6: | ||
356 | dprintk("%s: set FEC to 5/6\n",__FUNCTION__); | 364 | dprintk("%s: set FEC to 5/6\n",__FUNCTION__); |
357 | return cx24123_writereg(state, 0x0f, 0x80); | 365 | cx24123_writereg(state, 0x0e, nom_reg | 0x05); |
366 | cx24123_writereg(state, 0x0f, 0x20); | ||
367 | break; | ||
368 | case FEC_6_7: | ||
369 | dprintk("%s: set FEC to 6/7\n",__FUNCTION__); | ||
370 | cx24123_writereg(state, 0x0e, nom_reg | 0x06); | ||
371 | cx24123_writereg(state, 0x0f, 0x40); | ||
372 | break; | ||
373 | case FEC_7_8: | ||
374 | dprintk("%s: set FEC to 7/8\n",__FUNCTION__); | ||
375 | cx24123_writereg(state, 0x0e, nom_reg | 0x07); | ||
376 | cx24123_writereg(state, 0x0f, 0x80); | ||
377 | break; | ||
358 | case FEC_AUTO: | 378 | case FEC_AUTO: |
359 | dprintk("%s: set FEC to auto\n",__FUNCTION__); | 379 | dprintk("%s: set FEC to auto\n",__FUNCTION__); |
360 | return cx24123_writereg(state, 0x0f, 0xae); | 380 | cx24123_writereg(state, 0x0f, 0xfe); |
381 | break; | ||
361 | default: | 382 | default: |
362 | return -EOPNOTSUPP; | 383 | return -EOPNOTSUPP; |
363 | } | 384 | } |
385 | |||
386 | return 0; | ||
364 | } | 387 | } |
365 | 388 | ||
366 | static int cx24123_get_fec(struct cx24123_state* state, fe_code_rate_t *fec) | 389 | static int cx24123_get_fec(struct cx24123_state* state, fe_code_rate_t *fec) |
@@ -395,16 +418,31 @@ static int cx24123_get_fec(struct cx24123_state* state, fe_code_rate_t *fec) | |||
395 | *fec = FEC_7_8; | 418 | *fec = FEC_7_8; |
396 | break; | 419 | break; |
397 | default: | 420 | default: |
398 | *fec = FEC_NONE; // can't happen | 421 | /* this can happen when there's no lock */ |
399 | printk("FEC_NONE ?\n"); | 422 | *fec = FEC_NONE; |
400 | } | 423 | } |
401 | 424 | ||
402 | return 0; | 425 | return 0; |
403 | } | 426 | } |
404 | 427 | ||
428 | /* Approximation of closest integer of log2(a/b). It actually gives the | ||
429 | lowest integer i such that 2^i >= round(a/b) */ | ||
430 | static u32 cx24123_int_log2(u32 a, u32 b) | ||
431 | { | ||
432 | u32 exp, nearest = 0; | ||
433 | u32 div = a / b; | ||
434 | if(a % b >= b / 2) ++div; | ||
435 | if(div < (1 << 31)) | ||
436 | { | ||
437 | for(exp = 1; div > exp; nearest++) | ||
438 | exp += exp; | ||
439 | } | ||
440 | return nearest; | ||
441 | } | ||
442 | |||
405 | static int cx24123_set_symbolrate(struct cx24123_state* state, u32 srate) | 443 | static int cx24123_set_symbolrate(struct cx24123_state* state, u32 srate) |
406 | { | 444 | { |
407 | u32 tmp, sample_rate, ratio; | 445 | u32 tmp, sample_rate, ratio, sample_gain; |
408 | u8 pll_mult; | 446 | u8 pll_mult; |
409 | 447 | ||
410 | /* check if symbol rate is within limits */ | 448 | /* check if symbol rate is within limits */ |
@@ -462,7 +500,12 @@ static int cx24123_set_symbolrate(struct cx24123_state* state, u32 srate) | |||
462 | cx24123_writereg(state, 0x09, (ratio >> 8) & 0xff ); | 500 | cx24123_writereg(state, 0x09, (ratio >> 8) & 0xff ); |
463 | cx24123_writereg(state, 0x0a, (ratio ) & 0xff ); | 501 | cx24123_writereg(state, 0x0a, (ratio ) & 0xff ); |
464 | 502 | ||
465 | dprintk("%s: srate=%d, ratio=0x%08x, sample_rate=%i\n", __FUNCTION__, srate, ratio, sample_rate); | 503 | /* also set the demodulator sample gain */ |
504 | sample_gain = cx24123_int_log2(sample_rate, srate); | ||
505 | tmp = cx24123_readreg(state, 0x0c) & ~0xe0; | ||
506 | cx24123_writereg(state, 0x0c, tmp | sample_gain << 5); | ||
507 | |||
508 | dprintk("%s: srate=%d, ratio=0x%08x, sample_rate=%i sample_gain=%d\n", __FUNCTION__, srate, ratio, sample_rate, sample_gain); | ||
466 | 509 | ||
467 | return 0; | 510 | return 0; |
468 | } | 511 | } |
@@ -1014,12 +1057,13 @@ static struct dvb_frontend_ops cx24123_ops = { | |||
1014 | .frequency_min = 950000, | 1057 | .frequency_min = 950000, |
1015 | .frequency_max = 2150000, | 1058 | .frequency_max = 2150000, |
1016 | .frequency_stepsize = 1011, /* kHz for QPSK frontends */ | 1059 | .frequency_stepsize = 1011, /* kHz for QPSK frontends */ |
1017 | .frequency_tolerance = 29500, | 1060 | .frequency_tolerance = 5000, |
1018 | .symbol_rate_min = 1000000, | 1061 | .symbol_rate_min = 1000000, |
1019 | .symbol_rate_max = 45000000, | 1062 | .symbol_rate_max = 45000000, |
1020 | .caps = FE_CAN_INVERSION_AUTO | | 1063 | .caps = FE_CAN_INVERSION_AUTO | |
1021 | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | 1064 | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | |
1022 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | | 1065 | FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | |
1066 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | | ||
1023 | FE_CAN_QPSK | FE_CAN_RECOVER | 1067 | FE_CAN_QPSK | FE_CAN_RECOVER |
1024 | }, | 1068 | }, |
1025 | 1069 | ||