It is possible to provide both SNR and signal strength in
dB. Let's convert it to use the DVBv5 API and start showing
the SNR in dB.

Signed-off-by: Mauro Carvalho Chehab <mche...@s-opensource.com>
---
 drivers/media/dvb-frontends/au8522_dig.c  | 142 ++++++++++++++++++++++--------
 drivers/media/dvb-frontends/au8522_priv.h |   5 ++
 2 files changed, 108 insertions(+), 39 deletions(-)

diff --git a/drivers/media/dvb-frontends/au8522_dig.c 
b/drivers/media/dvb-frontends/au8522_dig.c
index ee14fd48c414..8a0764f605b0 100644
--- a/drivers/media/dvb-frontends/au8522_dig.c
+++ b/drivers/media/dvb-frontends/au8522_dig.c
@@ -641,9 +641,17 @@ static int au8522_set_frontend(struct dvb_frontend *fe)
 
        state->current_frequency = c->frequency;
 
+       /* Reset DVBv5 stats */
+       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;
+
        return 0;
 }
 
+static void au8522_get_stats(struct dvb_frontend *fe, enum fe_status status);
+
 static int au8522_read_status(struct dvb_frontend *fe, enum fe_status *status)
 {
        struct au8522_state *state = fe->demodulator_priv;
@@ -699,6 +707,8 @@ static int au8522_read_status(struct dvb_frontend *fe, enum 
fe_status *status)
 
        dprintk("%s() status 0x%08x\n", __func__, *status);
 
+       au8522_get_stats(fe, *status);
+
        return 0;
 }
 
@@ -764,70 +774,108 @@ static int au8522_read_snr(struct dvb_frontend *fe, u16 
*snr)
        return ret;
 }
 
-static int au8522_read_signal_strength(struct dvb_frontend *fe,
-                                      u16 *signal_strength)
+static void au8522_get_stats(struct dvb_frontend *fe, enum fe_status status)
 {
-       u16 snr;
-       u32 tmp;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       struct au8522_state *state = fe->demodulator_priv;
        int ret;
 
-       /* If the tuner has RF strength, use it */
+       /* Get S/N ratio */
+       if (status & FE_HAS_LOCK) {
+               ret = au8522_read_snr(fe, &state->snr);
+               if (ret < 0) {
+                       state->snr = 0;
+                       c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+               } else {
+                       c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+                       c->cnr.stat[0].svalue = state->snr * 100;
+               }
+       } else {
+               state->snr = 0;
+               c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       }
+
+       /* Get (or estimate) RF strength */
        if (fe->ops.tuner_ops.get_rf_strength) {
+               /* If the tuner has RF strength, use it */
+
                if (fe->ops.i2c_gate_ctrl)
                        fe->ops.i2c_gate_ctrl(fe, 1);
-               ret = fe->ops.tuner_ops.get_rf_strength(fe, signal_strength);
+               ret = fe->ops.tuner_ops.get_rf_strength(fe, &state->strength);
                if (fe->ops.i2c_gate_ctrl)
                        fe->ops.i2c_gate_ctrl(fe, 0);
-               return ret;
-       }
-
-       /*
-        * If it doen't, estimate from SNR
-        * (borrowed from lgdt330x.c)
-        *
-        * Calculate strength from SNR up to 35dB
-        * Even though the SNR can go higher than 35dB,
-        * there is some comfort factor in having a range of
-        * strong signals that can show at 100%
-        */
-       ret = au8522_read_snr(fe, &snr);
-
-       *signal_strength = 0;
-
-       if (0 == ret) {
-               /* The following calculation method was chosen
+               if (ret < 0)
+                       state->strength = 0;
+       } else {
+               u32 tmp;
+               /*
+                * If it doen't, estimate from SNR
+                * (borrowed from lgdt330x.c)
+                *
+                * Calculate strength from SNR up to 35dB
+                * Even though the SNR can go higher than 35dB,
+                * there is some comfort factor in having a range of
+                * strong signals that can show at 100%
+                *
+                * The following calculation method was chosen
                 * purely for the sake of code re-use from the
-                * other demod drivers that use this method */
+                * other demod drivers that use this method
+                */
 
                /* Convert from SNR in dB * 10 to 8.24 fixed-point */
-               tmp = (snr * ((1 << 24) / 10));
+               tmp = (state->snr * ((1 << 24) / 10));
 
                /* Convert from 8.24 fixed-point to
-                * scale the range 0 - 35*2^24 into 0 - 65535*/
+               * scale the range 0 - 35*2^24 into 0 - 65535*/
                if (tmp >= 8960 * 0x10000)
-                       *signal_strength = 0xffff;
+                       state->strength = 0xffff;
                else
-                       *signal_strength = tmp / 8960;
+                       state->strength = tmp / 8960;
        }
+       c->strength.stat[0].scale = FE_SCALE_RELATIVE;
+       c->strength.stat[0].uvalue = state->strength;
 
-       return ret;
-}
-
-static int au8522_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
-       struct au8522_state *state = fe->demodulator_priv;
+       /* Read UCB blocks */
+       if (!(status & FE_HAS_LOCK)) {
+               c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+               return;
+       }
 
        if (state->current_modulation == VSB_8)
-               *ucblocks = au8522_readreg(state, 0x4087);
+               state->ucblocks = au8522_readreg(state, 0x4087);
        else
-               *ucblocks = au8522_readreg(state, 0x4543);
+               state->ucblocks = au8522_readreg(state, 0x4543);
+
+       c->block_error.stat[0].scale = FE_SCALE_COUNTER;
+       c->block_error.stat[0].uvalue = state->ucblocks;
+}
+static int au8522_read_signal_strength(struct dvb_frontend *fe,
+                                      u16 *signal_strength)
+{
+       struct au8522_state *state = fe->demodulator_priv;
+
+       *signal_strength = state->strength;
+
+       return 0;
+}
+
+static int au8522_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+       struct au8522_state *state = fe->demodulator_priv;
+
+       *ucblocks = state->ucblocks;
 
        return 0;
 }
 
 static int au8522_read_ber(struct dvb_frontend *fe, u32 *ber)
 {
-       return au8522_read_ucblocks(fe, ber);
+       struct au8522_state *state = fe->demodulator_priv;
+
+       /* FIXME: This is so wrong! */
+       *ber = state->ucblocks;
+
+       return 0;
 }
 
 static int au8522_get_frontend(struct dvb_frontend *fe,
@@ -908,6 +956,22 @@ error:
 }
 EXPORT_SYMBOL(au8522_attach);
 
+static int au8522_dvb_init(struct dvb_frontend *fe)
+{
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+       /* Initialize DVBv5 statistics */
+       c->strength.stat[0].scale = FE_SCALE_RELATIVE;
+       c->strength.stat[0].uvalue = 0;
+       c->strength.len = 1;
+       c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       c->cnr.len = 1;
+       c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       c->block_error.len = 1;
+
+       return au8522_init(fe);
+}
+
 static struct dvb_frontend_ops au8522_ops = {
        .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
        .info = {
@@ -918,7 +982,7 @@ static struct dvb_frontend_ops au8522_ops = {
                .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
        },
 
-       .init                 = au8522_init,
+       .init                 = au8522_dvb_init,
        .sleep                = au8522_sleep,
        .i2c_gate_ctrl        = au8522_i2c_gate_ctrl,
        .set_frontend         = au8522_set_frontend,
diff --git a/drivers/media/dvb-frontends/au8522_priv.h 
b/drivers/media/dvb-frontends/au8522_priv.h
index f5a9438f6ce5..7b4f74997128 100644
--- a/drivers/media/dvb-frontends/au8522_priv.h
+++ b/drivers/media/dvb-frontends/au8522_priv.h
@@ -70,6 +70,11 @@ struct au8522_state {
        u32 rev;
        struct v4l2_ctrl_handler hdl;
 
+       /* Statistics */
+       u16 strength;
+       u16 snr;
+       u32 ucblocks;
+
 #ifdef CONFIG_MEDIA_CONTROLLER
        struct media_pad pads[DEMOD_NUM_PADS];
 #endif
-- 
2.7.4

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to