]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - drivers/media/dvb-frontends/si2168.c
Merge branches 'for-4.11/upstream-fixes', 'for-4.12/accutouch', 'for-4.12/cp2112...
[mirror_ubuntu-artful-kernel.git] / drivers / media / dvb-frontends / si2168.c
index 20b4a659e2e459dd9f536566f60c8fdda300eaa4..680ba06c29fb57610b6804d9b233f7a4458ada23 100644 (file)
@@ -85,7 +85,8 @@ static int si2168_read_status(struct dvb_frontend *fe, enum fe_status *status)
        struct i2c_client *client = fe->demodulator_priv;
        struct si2168_dev *dev = i2c_get_clientdata(client);
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-       int ret;
+       int ret, i;
+       unsigned int utmp, utmp1, utmp2;
        struct si2168_cmd cmd;
 
        *status = 0;
@@ -144,6 +145,61 @@ static int si2168_read_status(struct dvb_frontend *fe, enum fe_status *status)
        dev_dbg(&client->dev, "status=%02x args=%*ph\n",
                        *status, cmd.rlen, cmd.args);
 
+       /* BER */
+       if (*status & FE_HAS_VITERBI) {
+               memcpy(cmd.args, "\x82\x00", 2);
+               cmd.wlen = 2;
+               cmd.rlen = 3;
+               ret = si2168_cmd_execute(client, &cmd);
+               if (ret)
+                       goto err;
+
+               /*
+                * Firmware returns [0, 255] mantissa and [0, 8] exponent.
+                * Convert to DVB API: mantissa * 10^(8 - exponent) / 10^8
+                */
+               utmp = clamp(8 - cmd.args[1], 0, 8);
+               for (i = 0, utmp1 = 1; i < utmp; i++)
+                       utmp1 = utmp1 * 10;
+
+               utmp1 = cmd.args[2] * utmp1;
+               utmp2 = 100000000; /* 10^8 */
+
+               dev_dbg(&client->dev,
+                       "post_bit_error=%u post_bit_count=%u ber=%u*10^-%u\n",
+                       utmp1, utmp2, cmd.args[2], cmd.args[1]);
+
+               c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+               c->post_bit_error.stat[0].uvalue += utmp1;
+               c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+               c->post_bit_count.stat[0].uvalue += utmp2;
+       } else {
+               c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+               c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       }
+
+       /* UCB */
+       if (*status & FE_HAS_SYNC) {
+               memcpy(cmd.args, "\x84\x01", 2);
+               cmd.wlen = 2;
+               cmd.rlen = 3;
+               ret = si2168_cmd_execute(client, &cmd);
+               if (ret)
+                       goto err;
+
+               utmp1 = cmd.args[2] << 8 | cmd.args[1] << 0;
+               dev_dbg(&client->dev, "block_error=%u\n", utmp1);
+
+               /* Sometimes firmware returns bogus value */
+               if (utmp1 == 0xffff)
+                       utmp1 = 0;
+
+               c->block_error.stat[0].scale = FE_SCALE_COUNTER;
+               c->block_error.stat[0].uvalue += utmp1;
+       } else {
+               c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       }
+
        return 0;
 err:
        dev_dbg(&client->dev, "failed=%d\n", ret);
@@ -355,6 +411,7 @@ static int si2168_init(struct dvb_frontend *fe)
 {
        struct i2c_client *client = fe->demodulator_priv;
        struct si2168_dev *dev = i2c_get_clientdata(client);
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        int ret, len, remaining;
        const struct firmware *fw;
        struct si2168_cmd cmd;
@@ -493,10 +550,19 @@ static int si2168_init(struct dvb_frontend *fe)
 
        dev->warm = true;
 warm:
+       /* Init stats here to indicate which stats are supported */
+       c->cnr.len = 1;
+       c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       c->post_bit_error.len = 1;
+       c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       c->post_bit_count.len = 1;
+       c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       c->block_error.len = 1;
+       c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+
        dev->active = true;
 
        return 0;
-
 err_release_firmware:
        release_firmware(fw);
 err: