[media] tuner, xc2028: add support for get_afc()
authorMauro Carvalho Chehab <mchehab@redhat.com>
Wed, 4 Jul 2012 05:33:55 +0000 (02:33 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Wed, 4 Jul 2012 05:46:58 +0000 (02:46 -0300)
Implement API support to return AFC frequency shift, as this device
supports it. The only other driver that implements it is tda9887,
and the frequency there is reported in Hz. So, use Hz also for this
tuner.

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/common/tuners/tuner-xc2028.c
drivers/media/dvb/dvb-core/dvb_frontend.h
drivers/media/video/tuner-core.c

index 42fdf5c57091c77b51bc84650a5759b1b524557e..4857e86259a1da77d3cb39e9469f52a61e9b9db9 100644 (file)
@@ -924,7 +924,7 @@ static int xc2028_signal(struct dvb_frontend *fe, u16 *strength)
                msleep(6);
        }
 
-       /* Frequency was not locked */
+       /* Frequency didn't lock */
        if (frq_lock == 2)
                goto ret;
 
@@ -947,6 +947,49 @@ ret:
        return rc;
 }
 
+static int xc2028_get_afc(struct dvb_frontend *fe, s32 *afc)
+{
+       struct xc2028_data *priv = fe->tuner_priv;
+       int i, rc;
+       u16 frq_lock = 0;
+       s16 afc_reg = 0;
+
+       rc = check_device_status(priv);
+       if (rc < 0)
+               return rc;
+
+       mutex_lock(&priv->lock);
+
+       /* Sync Lock Indicator */
+       for (i = 0; i < 3; i++) {
+               rc = xc2028_get_reg(priv, XREG_LOCK, &frq_lock);
+               if (rc < 0)
+                       goto ret;
+
+               if (frq_lock)
+                       break;
+               msleep(6);
+       }
+
+       /* Frequency didn't lock */
+       if (frq_lock == 2)
+               goto ret;
+
+       /* Get AFC */
+       rc = xc2028_get_reg(priv, XREG_FREQ_ERROR, &afc_reg);
+       if (rc < 0)
+               return rc;
+
+       *afc = afc_reg * 15625; /* Hz */
+
+       tuner_dbg("AFC is %d Hz\n", *afc);
+
+ret:
+       mutex_unlock(&priv->lock);
+
+       return rc;
+}
+
 #define DIV 15625
 
 static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
@@ -1392,6 +1435,7 @@ static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = {
        .release           = xc2028_dvb_release,
        .get_frequency     = xc2028_get_frequency,
        .get_rf_strength   = xc2028_signal,
+       .get_afc           = xc2028_get_afc,
        .set_params        = xc2028_set_params,
        .sleep             = xc2028_sleep,
 };
index e929d5697b8799bb8597d09dd620dc510dd282dc..7c64c09103a94d1e15f7b57c32ae21da4720e716 100644 (file)
@@ -220,6 +220,7 @@ struct dvb_tuner_ops {
 #define TUNER_STATUS_STEREO 2
        int (*get_status)(struct dvb_frontend *fe, u32 *status);
        int (*get_rf_strength)(struct dvb_frontend *fe, u16 *strength);
+       int (*get_afc)(struct dvb_frontend *fe, s32 *afc);
 
        /** These are provided separately from set_params in order to facilitate silicon
         * tuners which require sophisticated tuning loops, controlling each parameter separately. */
index 98adeeebb8b08d4494985adab2ba0e31df49b9cd..b5a819af2b8c4c3c36ae00fdf2eb7334863de030 100644 (file)
@@ -228,6 +228,16 @@ static int fe_has_signal(struct dvb_frontend *fe)
        return strength;
 }
 
+static int fe_get_afc(struct dvb_frontend *fe)
+{
+       s32 afc = 0;
+
+       if (fe->ops.tuner_ops.get_afc)
+               fe->ops.tuner_ops.get_afc(fe, &afc);
+
+       return 0;
+}
+
 static int fe_set_config(struct dvb_frontend *fe, void *priv_cfg)
 {
        struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
@@ -247,6 +257,7 @@ static struct analog_demod_ops tuner_analog_ops = {
        .set_params     = fe_set_params,
        .standby        = fe_standby,
        .has_signal     = fe_has_signal,
+       .get_afc        = fe_get_afc,
        .set_config     = fe_set_config,
        .tuner_status   = tuner_status
 };