aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2013-03-20 07:21:52 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2013-03-21 09:27:05 -0400
commit59a7a23c4755f12757fe17234c693188a9e6bcf5 (patch)
treee202191ff14e7876c0548d6e6397354a592c49de
parent8f3741e02831d1181be9ca0ea711dd0c8d7f8a7b (diff)
[media] drxk: use a better calculus for RF strength
The AZ6007 driver released by Terratec has a better way to estimate the signal strength, at CtrlSigStrength(). Port it to the driver. It should be noticed that there are two parameters there that are tuner-specific. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/dvb-frontends/drxk_hard.c126
1 files changed, 109 insertions, 17 deletions
diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c
index 8c4de7cc4500..6e250533b628 100644
--- a/drivers/media/dvb-frontends/drxk_hard.c
+++ b/drivers/media/dvb-frontends/drxk_hard.c
@@ -6390,6 +6390,107 @@ static int drxk_set_parameters(struct dvb_frontend *fe)
6390 return 0; 6390 return 0;
6391} 6391}
6392 6392
6393static int get_strength(struct drxk_state *state, u64 *strength)
6394{
6395 int status;
6396 struct SCfgAgc rfAgc, ifAgc;
6397 u32 totalGain = 0;
6398 u32 atten = 0;
6399 u32 agcRange = 0;
6400 u16 scu_lvl = 0;
6401 u16 scu_coc = 0;
6402 /* FIXME: those are part of the tuner presets */
6403 u16 tunerRfGain = 50; /* Default value on az6007 driver */
6404 u16 tunerIfGain = 40; /* Default value on az6007 driver */
6405
6406 *strength = 0;
6407
6408 if (IsDVBT(state)) {
6409 rfAgc = state->m_dvbtRfAgcCfg;
6410 ifAgc = state->m_dvbtIfAgcCfg;
6411 } else if (IsQAM(state)) {
6412 rfAgc = state->m_qamRfAgcCfg;
6413 ifAgc = state->m_qamIfAgcCfg;
6414 } else {
6415 rfAgc = state->m_atvRfAgcCfg;
6416 ifAgc = state->m_atvIfAgcCfg;
6417 }
6418
6419 if (rfAgc.ctrlMode == DRXK_AGC_CTRL_AUTO) {
6420 /* SCU outputLevel */
6421 status = read16(state, SCU_RAM_AGC_RF_IACCU_HI__A, &scu_lvl);
6422 if (status < 0)
6423 return status;
6424
6425 /* SCU c.o.c. */
6426 read16(state, SCU_RAM_AGC_RF_IACCU_HI_CO__A, &scu_coc);
6427 if (status < 0)
6428 return status;
6429
6430 if (((u32) scu_lvl + (u32) scu_coc) < 0xffff)
6431 rfAgc.outputLevel = scu_lvl + scu_coc;
6432 else
6433 rfAgc.outputLevel = 0xffff;
6434
6435 /* Take RF gain into account */
6436 totalGain += tunerRfGain;
6437
6438 /* clip output value */
6439 if (rfAgc.outputLevel < rfAgc.minOutputLevel)
6440 rfAgc.outputLevel = rfAgc.minOutputLevel;
6441 if (rfAgc.outputLevel > rfAgc.maxOutputLevel)
6442 rfAgc.outputLevel = rfAgc.maxOutputLevel;
6443
6444 agcRange = (u32) (rfAgc.maxOutputLevel - rfAgc.minOutputLevel);
6445 if (agcRange > 0) {
6446 atten += 100UL *
6447 ((u32)(tunerRfGain)) *
6448 ((u32)(rfAgc.outputLevel - rfAgc.minOutputLevel))
6449 / agcRange;
6450 }
6451 }
6452
6453 if (ifAgc.ctrlMode == DRXK_AGC_CTRL_AUTO) {
6454 status = read16(state, SCU_RAM_AGC_IF_IACCU_HI__A,
6455 &ifAgc.outputLevel);
6456 if (status < 0)
6457 return status;
6458
6459 status = read16(state, SCU_RAM_AGC_INGAIN_TGT_MIN__A,
6460 &ifAgc.top);
6461 if (status < 0)
6462 return status;
6463
6464 /* Take IF gain into account */
6465 totalGain += (u32) tunerIfGain;
6466
6467 /* clip output value */
6468 if (ifAgc.outputLevel < ifAgc.minOutputLevel)
6469 ifAgc.outputLevel = ifAgc.minOutputLevel;
6470 if (ifAgc.outputLevel > ifAgc.maxOutputLevel)
6471 ifAgc.outputLevel = ifAgc.maxOutputLevel;
6472
6473 agcRange = (u32) (ifAgc.maxOutputLevel - ifAgc.minOutputLevel);
6474 if (agcRange > 0) {
6475 atten += 100UL *
6476 ((u32)(tunerIfGain)) *
6477 ((u32)(ifAgc.outputLevel - ifAgc.minOutputLevel))
6478 / agcRange;
6479 }
6480 }
6481
6482 /*
6483 * Convert to 0..65535 scale.
6484 * If it can't be measured (AGC is disabled), just show 100%.
6485 */
6486 if (totalGain > 0)
6487 *strength = (65535UL * atten / totalGain);
6488 else
6489 *strength = 65535;
6490
6491 return 0;
6492}
6493
6393static int drxk_get_stats(struct dvb_frontend *fe) 6494static int drxk_get_stats(struct dvb_frontend *fe)
6394{ 6495{
6395 struct dtv_frontend_properties *c = &fe->dtv_property_cache; 6496 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
@@ -6404,7 +6505,7 @@ static int drxk_get_stats(struct dvb_frontend *fe)
6404 u32 pre_bit_count; 6505 u32 pre_bit_count;
6405 u32 pkt_count; 6506 u32 pkt_count;
6406 u32 pkt_error_count; 6507 u32 pkt_error_count;
6407 s32 cnr, gain; 6508 s32 cnr;
6408 6509
6409 if (state->m_DrxkState == DRXK_NO_DEV) 6510 if (state->m_DrxkState == DRXK_NO_DEV)
6410 return -ENODEV; 6511 return -ENODEV;
@@ -6421,6 +6522,13 @@ static int drxk_get_stats(struct dvb_frontend *fe)
6421 if (stat == DEMOD_LOCK) 6522 if (stat == DEMOD_LOCK)
6422 state->fe_status |= 0x07; 6523 state->fe_status |= 0x07;
6423 6524
6525 /*
6526 * Estimate signal strength from AGC
6527 */
6528 get_strength(state, &c->strength.stat[0].uvalue);
6529 c->strength.stat[0].scale = FE_SCALE_RELATIVE;
6530
6531
6424 if (stat >= DEMOD_LOCK) { 6532 if (stat >= DEMOD_LOCK) {
6425 GetSignalToNoise(state, &cnr); 6533 GetSignalToNoise(state, &cnr);
6426 c->cnr.stat[0].svalue = cnr * 100; 6534 c->cnr.stat[0].svalue = cnr * 100;
@@ -6500,22 +6608,6 @@ static int drxk_get_stats(struct dvb_frontend *fe)
6500 c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; 6608 c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
6501 c->post_bit_count.stat[0].uvalue += post_bit_count; 6609 c->post_bit_count.stat[0].uvalue += post_bit_count;
6502 6610
6503 /*
6504 * Read AGC gain
6505 *
6506 * IFgain = (IQM_AF_AGC_IF__A * 26.75) (nA)
6507 */
6508 status = read16(state, IQM_AF_AGC_IF__A, &reg16);
6509 if (status < 0) {
6510 printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
6511 return status;
6512 }
6513 gain = 2675 * (reg16 - DRXK_AGC_DAC_OFFSET) / 100;
6514
6515 /* FIXME: it makes sense to fix the scale here to dBm */
6516 c->strength.stat[0].scale = FE_SCALE_RELATIVE;
6517 c->strength.stat[0].uvalue = gain;
6518
6519error: 6611error:
6520 return status; 6612 return status;
6521} 6613}