[media] dib8000: add DVBv5 stats

The advantage of DVBv5 stats is that it allows adding proper
scales to all measures. use it for this frontend.

This patch adds a basic set of stats, basically cloning what's already
provided by DVBv3 API. Latter patches will improve it.

Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
Acked-by: Patrick Boettcher <pboettcher@kernellabs.com>
This commit is contained in:
Mauro Carvalho Chehab 2013-12-16 19:10:59 -03:00
parent 51fea11342
commit 6ef06e78c7
1 changed files with 141 additions and 1 deletions

View File

@ -124,6 +124,8 @@ struct dib8000_state {
u16 agc2_max;
u16 agc2_min;
#endif
unsigned long get_stats_time;
};
enum dib8000_power_mode {
@ -804,7 +806,7 @@ int dib8000_update_pll(struct dvb_frontend *fe,
dprintk("PLL: Update ratio (prediv: %d, ratio: %d)", state->cfg.pll->pll_prediv, ratio);
dib8000_write_word(state, 901, (state->cfg.pll->pll_prediv << 8) | (ratio << 0)); /* only the PLL ratio is updated. */
}
}
}
return 0;
}
@ -983,6 +985,32 @@ static u16 dib8000_identify(struct i2c_device *client)
return value;
}
static void dib8000_reset_stats(struct dvb_frontend *fe)
{
struct dib8000_state *state = fe->demodulator_priv;
struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
memset(&c->strength, 0, sizeof(c->strength));
memset(&c->cnr, 0, sizeof(c->cnr));
memset(&c->post_bit_error, 0, sizeof(c->post_bit_error));
memset(&c->post_bit_count, 0, sizeof(c->post_bit_count));
memset(&c->block_error, 0, sizeof(c->block_error));
c->strength.len = 1;
c->cnr.len = 1;
c->block_error.len = 1;
c->post_bit_error.len = 1;
c->post_bit_count.len = 1;
c->strength.stat[0].scale = FE_SCALE_RELATIVE;
c->strength.stat[0].uvalue = 0;
c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
}
static int dib8000_reset(struct dvb_frontend *fe)
{
struct dib8000_state *state = fe->demodulator_priv;
@ -1088,6 +1116,8 @@ static int dib8000_reset(struct dvb_frontend *fe)
dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
dib8000_reset_stats(fe);
return 0;
}
@ -2983,6 +3013,8 @@ static int dib8000_tune(struct dvb_frontend *fe)
switch (*tune_state) {
case CT_DEMOD_START: /* 30 */
dib8000_reset_stats(fe);
if (state->revision == 0x8090)
dib8090p_init_sdram(state);
state->status = FE_STATUS_TUNE_PENDING;
@ -3654,6 +3686,8 @@ static int dib8000_set_frontend(struct dvb_frontend *fe)
return 0;
}
static int dib8000_get_stats(struct dvb_frontend *fe, fe_status_t stat);
static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
{
struct dib8000_state *state = fe->demodulator_priv;
@ -3691,6 +3725,7 @@ static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
if (lock & 0x01)
*stat |= FE_HAS_VITERBI;
}
dib8000_get_stats(fe, *stat);
return 0;
}
@ -3797,6 +3832,111 @@ static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr)
return 0;
}
struct per_layer_regs {
u16 lock, ber, per;
};
static const struct per_layer_regs per_layer_regs[] = {
{ 554, 560, 562 },
{ 555, 576, 578 },
{ 556, 581, 583 },
};
static int dib8000_get_stats(struct dvb_frontend *fe, fe_status_t stat)
{
struct dib8000_state *state = fe->demodulator_priv;
struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
int i, lock;
u32 snr, val;
u16 strength;
/* Get Signal strength */
dib8000_read_signal_strength(fe, &strength);
c->strength.stat[0].uvalue = strength;
/* Check if 1 second was elapsed */
if (!time_after(jiffies, state->get_stats_time))
return 0;
state->get_stats_time = jiffies + msecs_to_jiffies(1000);
/* Get SNR */
snr = dib8000_get_snr(fe);
for (i = 1; i < MAX_NUMBER_OF_FRONTENDS; i++) {
if (state->fe[i])
snr += dib8000_get_snr(state->fe[i]);
}
snr = snr >> 16;
if (snr) {
snr = 10 * intlog10(snr);
snr = (1000L * snr) >> 24;
} else {
snr = 0;
}
c->cnr.stat[0].svalue = snr;
c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
/* UCB/BER measures require lock */
if (!(stat & FE_HAS_LOCK)) {
c->block_error.len = 1;
c->post_bit_error.len = 1;
c->post_bit_count.len = 1;
c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
return 0;
}
/* Get UCB and post-BER measures */
/* FIXME: need to check if 1.25e6 bits already passed */
dib8000_read_ber(fe, &val);
c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
c->post_bit_error.stat[0].uvalue += val;
c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
c->post_bit_count.stat[0].uvalue += 100000000;
/*
* FIXME: this is refreshed on every second, but a time
* drift between dib8000 and PC clock may cause troubles
*/
dib8000_read_unc_blocks(fe, &val);
c->block_error.stat[0].scale = FE_SCALE_COUNTER;
c->block_error.stat[0].uvalue += val;
if (state->revision < 0x8002)
return 0;
c->block_error.len = 4;
c->post_bit_error.len = 4;
c->post_bit_count.len = 4;
for (i = 0; i < 3; i++) {
lock = dib8000_read_word(state, per_layer_regs[i].lock);
if (lock & 0x01) {
/* FIXME: need to check if 1.25e6 bits already passed */
val = dib8000_read_word(state, per_layer_regs[i].ber);
c->post_bit_error.stat[1 + i].scale = FE_SCALE_COUNTER;
c->post_bit_error.stat[1 + i].uvalue += val;
c->post_bit_count.stat[1 + i].scale = FE_SCALE_COUNTER;
c->post_bit_count.stat[1 + i].uvalue += 100000000;
/*
* FIXME: this is refreshed on every second, but a time
* drift between dib8000 and PC clock may cause troubles
*/
val = dib8000_read_word(state, per_layer_regs[i].per);
c->block_error.stat[1 + i].scale = FE_SCALE_COUNTER;
c->block_error.stat[1 + i].uvalue += val;
}
}
return 0;
}
int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
{
struct dib8000_state *state = fe->demodulator_priv;