[media] af9033: implement DVBv5 statistics for signal strength
authorAntti Palosaari <crope@iki.fi>
Tue, 2 Sep 2014 06:55:21 +0000 (03:55 -0300)
committerMauro Carvalho Chehab <mchehab@osg.samsung.com>
Sun, 21 Sep 2014 22:44:43 +0000 (19:44 -0300)
Let the demod firmware estimate RF signal strength and return it
to the app as a dBm. To handle that, use thread which reads signal
strengths from firmware in 2 sec intervals when device is active.

Signed-off-by: Antti Palosaari <crope@iki.fi>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
drivers/media/dvb-frontends/af9033.c

index 1bd5a9af7db58a9deeb25e34450e53cc74393cdf..b9a0b009aeda792179de4861b7c1de60a69eed24 100644 (file)
@@ -28,13 +28,17 @@ struct af9033_dev {
        struct i2c_client *client;
        struct dvb_frontend fe;
        struct af9033_config cfg;
+       bool is_af9035;
+       bool is_it9135;
 
        u32 bandwidth_hz;
        bool ts_mode_parallel;
        bool ts_mode_serial;
 
+       fe_status_t fe_status;
        u32 ber;
        u32 ucb;
+       struct delayed_work stat_work;
        unsigned long last_stat_check;
 };
 
@@ -442,6 +446,8 @@ static int af9033_init(struct dvb_frontend *fe)
        }
 
        dev->bandwidth_hz = 0; /* force to program all parameters */
+       /* start statistics polling */
+       schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000));
 
        return 0;
 
@@ -457,6 +463,9 @@ static int af9033_sleep(struct dvb_frontend *fe)
        int ret, i;
        u8 tmp;
 
+       /* stop statistics polling */
+       cancel_delayed_work_sync(&dev->stat_work);
+
        ret = af9033_wr_reg(dev, 0x80004c, 1);
        if (ret < 0)
                goto err;
@@ -810,6 +819,8 @@ static int af9033_read_status(struct dvb_frontend *fe, fe_status_t *status)
                                        FE_HAS_LOCK;
        }
 
+       dev->fe_status = *status;
+
        return 0;
 
 err:
@@ -1039,6 +1050,40 @@ err:
        return ret;
 }
 
+static void af9033_stat_work(struct work_struct *work)
+{
+       struct af9033_dev *dev = container_of(work, struct af9033_dev, stat_work.work);
+       struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache;
+       int ret, tmp;
+       u8 u8tmp;
+
+       dev_dbg(&dev->client->dev, "\n");
+
+       if (dev->fe_status & FE_HAS_SIGNAL) {
+               if (dev->is_af9035) {
+                       ret = af9033_rd_reg(dev, 0x80004a, &u8tmp);
+                       tmp = -u8tmp * 1000;
+               } else {
+                       ret = af9033_rd_reg(dev, 0x8000f7, &u8tmp);
+                       tmp = (u8tmp - 100) * 1000;
+               }
+               if (ret)
+                       goto err;
+
+               c->strength.len = 1;
+               c->strength.stat[0].scale = FE_SCALE_DECIBEL;
+               c->strength.stat[0].svalue = tmp;
+       } else {
+               c->strength.len = 1;
+               c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       }
+
+       schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000));
+       return;
+err:
+       dev_dbg(&dev->client->dev, "failed=%d\n", ret);
+}
+
 static struct dvb_frontend_ops af9033_ops = {
        .delsys = { SYS_DVBT },
        .info = {
@@ -1099,6 +1144,7 @@ static int af9033_probe(struct i2c_client *client,
 
        /* setup the state */
        dev->client = client;
+       INIT_DELAYED_WORK(&dev->stat_work, af9033_stat_work);
        memcpy(&dev->cfg, cfg, sizeof(struct af9033_config));
 
        if (dev->cfg.clock != 12000000) {
@@ -1117,9 +1163,11 @@ static int af9033_probe(struct i2c_client *client,
        case AF9033_TUNER_IT9135_60:
        case AF9033_TUNER_IT9135_61:
        case AF9033_TUNER_IT9135_62:
+               dev->is_it9135 = true;
                reg = 0x004bfc;
                break;
        default:
+               dev->is_af9035 = true;
                reg = 0x0083e9;
                break;
        }