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