diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-01-17 18:10:47 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-01-24 11:24:59 -0500 |
commit | 593ae89a3f2ea69b0cffb8d8ca63549c6c02ec19 (patch) | |
tree | 9a9c5eeefc9adeadf692a2cdef9ce03be5d4ba30 | |
parent | 94a93e5f85040114d6a77c085457b3943b6da889 (diff) |
[media] mb86a20s: add block count measures (PER/UCB)
Add both per-layer and global block error count and block count,
for PER and UCB measurements.
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | drivers/media/dvb-frontends/mb86a20s.c | 190 |
1 files changed, 180 insertions, 10 deletions
diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index 4f3e222a2bcf..c5c2c49ea99a 100644 --- a/drivers/media/dvb-frontends/mb86a20s.c +++ b/drivers/media/dvb-frontends/mb86a20s.c | |||
@@ -111,13 +111,21 @@ static struct regdata mb86a20s_init[] = { | |||
111 | { 0x50, 0xdf }, { 0x51, 0xf4 }, | 111 | { 0x50, 0xdf }, { 0x51, 0xf4 }, |
112 | { 0x50, 0xe0 }, { 0x51, 0x01 }, | 112 | { 0x50, 0xe0 }, { 0x51, 0x01 }, |
113 | { 0x50, 0xe1 }, { 0x51, 0xf4 }, | 113 | { 0x50, 0xe1 }, { 0x51, 0xf4 }, |
114 | { 0x50, 0xb0 }, { 0x51, 0x07 }, | 114 | |
115 | { 0x50, 0xb2 }, { 0x51, 0xff }, | 115 | /* |
116 | { 0x50, 0xb3 }, { 0x51, 0xff }, | 116 | * On this demod, when the block count reaches the count below, |
117 | { 0x50, 0xb4 }, { 0x51, 0xff }, | 117 | * it collects the block error count. The block counters are initialized |
118 | { 0x50, 0xb5 }, { 0x51, 0xff }, | 118 | * to 127 here. This warrants that all of them will be quickly |
119 | { 0x50, 0xb6 }, { 0x51, 0xff }, | 119 | * calculated when device gets locked. As TMCC is parsed, the values |
120 | { 0x50, 0xb7 }, { 0x51, 0xff }, | 120 | * will be adjusted later in the driver's code. |
121 | */ | ||
122 | { 0x50, 0xb0 }, { 0x51, 0x07 }, /* Enable PER */ | ||
123 | { 0x50, 0xb2 }, { 0x51, 0x00 }, | ||
124 | { 0x50, 0xb3 }, { 0x51, 0x7f }, | ||
125 | { 0x50, 0xb4 }, { 0x51, 0x00 }, | ||
126 | { 0x50, 0xb5 }, { 0x51, 0x7f }, | ||
127 | { 0x50, 0xb6 }, { 0x51, 0x00 }, | ||
128 | { 0x50, 0xb7 }, { 0x51, 0x7f }, | ||
121 | 129 | ||
122 | { 0x50, 0x50 }, { 0x51, 0x02 }, /* MER manual mode */ | 130 | { 0x50, 0x50 }, { 0x51, 0x02 }, /* MER manual mode */ |
123 | { 0x50, 0x51 }, { 0x51, 0x04 }, /* MER symbol 4 */ | 131 | { 0x50, 0x51 }, { 0x51, 0x04 }, /* MER symbol 4 */ |
@@ -893,6 +901,123 @@ static int mb86a20s_get_ber_before_vterbi(struct dvb_frontend *fe, | |||
893 | return 0; | 901 | return 0; |
894 | } | 902 | } |
895 | 903 | ||
904 | static int mb86a20s_get_blk_error(struct dvb_frontend *fe, | ||
905 | unsigned layer, | ||
906 | u32 *error, u32 *count) | ||
907 | { | ||
908 | struct mb86a20s_state *state = fe->demodulator_priv; | ||
909 | int rc; | ||
910 | u32 collect_rate; | ||
911 | dev_dbg(&state->i2c->dev, "%s called.\n", __func__); | ||
912 | |||
913 | if (layer >= 3) | ||
914 | return -EINVAL; | ||
915 | |||
916 | /* Check if the PER measures are already available */ | ||
917 | rc = mb86a20s_writereg(state, 0x50, 0xb8); | ||
918 | if (rc < 0) | ||
919 | return rc; | ||
920 | rc = mb86a20s_readreg(state, 0x51); | ||
921 | if (rc < 0) | ||
922 | return rc; | ||
923 | |||
924 | /* Check if data is available for that layer */ | ||
925 | |||
926 | if (!(rc & (1 << layer))) { | ||
927 | dev_dbg(&state->i2c->dev, | ||
928 | "%s: block counts for layer %c aren't available yet.\n", | ||
929 | __func__, 'A' + layer); | ||
930 | return -EBUSY; | ||
931 | } | ||
932 | |||
933 | /* Read Packet error Count */ | ||
934 | rc = mb86a20s_writereg(state, 0x50, 0xb9 + layer * 2); | ||
935 | if (rc < 0) | ||
936 | return rc; | ||
937 | rc = mb86a20s_readreg(state, 0x51); | ||
938 | if (rc < 0) | ||
939 | return rc; | ||
940 | *error = rc << 8; | ||
941 | rc = mb86a20s_writereg(state, 0x50, 0xba + layer * 2); | ||
942 | if (rc < 0) | ||
943 | return rc; | ||
944 | rc = mb86a20s_readreg(state, 0x51); | ||
945 | if (rc < 0) | ||
946 | return rc; | ||
947 | *error |= rc; | ||
948 | dev_err(&state->i2c->dev, "%s: block error for layer %c: %d.\n", | ||
949 | __func__, 'A' + layer, *error); | ||
950 | |||
951 | /* Read Bit Count */ | ||
952 | rc = mb86a20s_writereg(state, 0x50, 0xb2 + layer * 2); | ||
953 | if (rc < 0) | ||
954 | return rc; | ||
955 | rc = mb86a20s_readreg(state, 0x51); | ||
956 | if (rc < 0) | ||
957 | return rc; | ||
958 | *count = rc << 8; | ||
959 | rc = mb86a20s_writereg(state, 0x50, 0xb3 + layer * 2); | ||
960 | if (rc < 0) | ||
961 | return rc; | ||
962 | rc = mb86a20s_readreg(state, 0x51); | ||
963 | if (rc < 0) | ||
964 | return rc; | ||
965 | *count |= rc; | ||
966 | |||
967 | dev_dbg(&state->i2c->dev, | ||
968 | "%s: block count for layer %c: %d.\n", | ||
969 | __func__, 'A' + layer, *count); | ||
970 | |||
971 | /* | ||
972 | * As we get TMCC data from the frontend, we can better estimate the | ||
973 | * BER bit counters, in order to do the BER measure during a longer | ||
974 | * time. Use those data, if available, to update the bit count | ||
975 | * measure. | ||
976 | */ | ||
977 | |||
978 | if (!state->estimated_rate[layer]) | ||
979 | goto reset_measurement; | ||
980 | |||
981 | collect_rate = state->estimated_rate[layer] / 204 / 8; | ||
982 | |||
983 | if (collect_rate < 32) | ||
984 | collect_rate = 32; | ||
985 | if (collect_rate > 65535) | ||
986 | collect_rate = 65535; | ||
987 | |||
988 | if (collect_rate != *count) { | ||
989 | dev_dbg(&state->i2c->dev, | ||
990 | "%s: updating PER counter on layer %c to %d.\n", | ||
991 | __func__, 'A' + layer, collect_rate); | ||
992 | rc = mb86a20s_writereg(state, 0x50, 0xb2 + layer * 2); | ||
993 | if (rc < 0) | ||
994 | return rc; | ||
995 | rc = mb86a20s_writereg(state, 0x51, collect_rate >> 8); | ||
996 | if (rc < 0) | ||
997 | return rc; | ||
998 | rc = mb86a20s_writereg(state, 0x50, 0xb3 + layer * 2); | ||
999 | if (rc < 0) | ||
1000 | return rc; | ||
1001 | rc = mb86a20s_writereg(state, 0x51, collect_rate & 0xff); | ||
1002 | if (rc < 0) | ||
1003 | return rc; | ||
1004 | } | ||
1005 | |||
1006 | reset_measurement: | ||
1007 | /* Reset counter to collect new data */ | ||
1008 | rc = mb86a20s_writereg(state, 0x50, 0xb1); | ||
1009 | if (rc < 0) | ||
1010 | return rc; | ||
1011 | rc = mb86a20s_writereg(state, 0x51, (1 << layer)); | ||
1012 | if (rc < 0) | ||
1013 | return rc; | ||
1014 | rc = mb86a20s_writereg(state, 0x51, 0x00); | ||
1015 | if (rc < 0) | ||
1016 | return rc; | ||
1017 | |||
1018 | return 0; | ||
1019 | } | ||
1020 | |||
896 | struct linear_segments { | 1021 | struct linear_segments { |
897 | unsigned x, y; | 1022 | unsigned x, y; |
898 | }; | 1023 | }; |
@@ -1115,7 +1240,7 @@ static int mb86a20s_get_main_CNR(struct dvb_frontend *fe) | |||
1115 | return rc; | 1240 | return rc; |
1116 | } | 1241 | } |
1117 | 1242 | ||
1118 | static int mb86a20s_get_per_layer_CNR(struct dvb_frontend *fe) | 1243 | static int mb86a20s_get_blk_error_layer_CNR(struct dvb_frontend *fe) |
1119 | { | 1244 | { |
1120 | struct mb86a20s_state *state = fe->demodulator_priv; | 1245 | struct mb86a20s_state *state = fe->demodulator_priv; |
1121 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | 1246 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
@@ -1258,14 +1383,16 @@ static int mb86a20s_get_stats(struct dvb_frontend *fe) | |||
1258 | int rc = 0, i; | 1383 | int rc = 0, i; |
1259 | u32 bit_error = 0, bit_count = 0; | 1384 | u32 bit_error = 0, bit_count = 0; |
1260 | u32 t_pre_bit_error = 0, t_pre_bit_count = 0; | 1385 | u32 t_pre_bit_error = 0, t_pre_bit_count = 0; |
1261 | int active_layers = 0, ber_layers = 0; | 1386 | u32 block_error = 0, block_count = 0; |
1387 | u32 t_block_error = 0, t_block_count = 0; | ||
1388 | int active_layers = 0, ber_layers = 0, per_layers = 0; | ||
1262 | 1389 | ||
1263 | dev_dbg(&state->i2c->dev, "%s called.\n", __func__); | 1390 | dev_dbg(&state->i2c->dev, "%s called.\n", __func__); |
1264 | 1391 | ||
1265 | mb86a20s_get_main_CNR(fe); | 1392 | mb86a20s_get_main_CNR(fe); |
1266 | 1393 | ||
1267 | /* Get per-layer stats */ | 1394 | /* Get per-layer stats */ |
1268 | mb86a20s_get_per_layer_CNR(fe); | 1395 | mb86a20s_get_blk_error_layer_CNR(fe); |
1269 | 1396 | ||
1270 | for (i = 0; i < 3; i++) { | 1397 | for (i = 0; i < 3; i++) { |
1271 | if (c->isdbt_layer_enabled & (1 << i)) { | 1398 | if (c->isdbt_layer_enabled & (1 << i)) { |
@@ -1297,9 +1424,38 @@ static int mb86a20s_get_stats(struct dvb_frontend *fe) | |||
1297 | if (c->block_error.stat[1 + i].scale != FE_SCALE_NOT_AVAILABLE) | 1424 | if (c->block_error.stat[1 + i].scale != FE_SCALE_NOT_AVAILABLE) |
1298 | ber_layers++; | 1425 | ber_layers++; |
1299 | 1426 | ||
1427 | /* Handle Block errors for PER/UCB reports */ | ||
1428 | rc = mb86a20s_get_blk_error(fe, i, | ||
1429 | &block_error, | ||
1430 | &block_count); | ||
1431 | if (rc >= 0) { | ||
1432 | c->block_error.stat[1 + i].scale = FE_SCALE_COUNTER; | ||
1433 | c->block_error.stat[1 + i].uvalue += block_error; | ||
1434 | c->block_count.stat[1 + i].scale = FE_SCALE_COUNTER; | ||
1435 | c->block_count.stat[1 + i].uvalue += block_count; | ||
1436 | } else if (rc != -EBUSY) { | ||
1437 | /* | ||
1438 | * If an I/O error happened, | ||
1439 | * measures are now unavailable | ||
1440 | */ | ||
1441 | c->block_error.stat[1 + i].scale = FE_SCALE_NOT_AVAILABLE; | ||
1442 | c->block_count.stat[1 + i].scale = FE_SCALE_NOT_AVAILABLE; | ||
1443 | dev_err(&state->i2c->dev, | ||
1444 | "%s: Can't get PER for layer %c (error %d).\n", | ||
1445 | __func__, 'A' + i, rc); | ||
1446 | |||
1447 | } | ||
1448 | |||
1449 | if (c->block_error.stat[1 + i].scale != FE_SCALE_NOT_AVAILABLE) | ||
1450 | per_layers++; | ||
1451 | |||
1300 | /* Update total BER */ | 1452 | /* Update total BER */ |
1301 | t_pre_bit_error += c->pre_bit_error.stat[1 + i].uvalue; | 1453 | t_pre_bit_error += c->pre_bit_error.stat[1 + i].uvalue; |
1302 | t_pre_bit_count += c->pre_bit_count.stat[1 + i].uvalue; | 1454 | t_pre_bit_count += c->pre_bit_count.stat[1 + i].uvalue; |
1455 | |||
1456 | /* Update total PER */ | ||
1457 | t_block_error += c->block_error.stat[1 + i].uvalue; | ||
1458 | t_block_count += c->block_count.stat[1 + i].uvalue; | ||
1303 | } | 1459 | } |
1304 | } | 1460 | } |
1305 | 1461 | ||
@@ -1321,6 +1477,20 @@ static int mb86a20s_get_stats(struct dvb_frontend *fe) | |||
1321 | c->pre_bit_count.stat[0].uvalue = t_pre_bit_count; | 1477 | c->pre_bit_count.stat[0].uvalue = t_pre_bit_count; |
1322 | } | 1478 | } |
1323 | 1479 | ||
1480 | if (per_layers) { | ||
1481 | /* | ||
1482 | * At least one per-layer UCB measure was read. We can now | ||
1483 | * calculate the total UCB | ||
1484 | * | ||
1485 | * Total block Error/Count is calculated as the sum of the | ||
1486 | * block errors on all active layers. | ||
1487 | */ | ||
1488 | c->block_error.stat[0].scale = FE_SCALE_COUNTER; | ||
1489 | c->block_error.stat[0].uvalue = t_block_error; | ||
1490 | c->block_count.stat[0].scale = FE_SCALE_COUNTER; | ||
1491 | c->block_count.stat[0].uvalue = t_block_count; | ||
1492 | } | ||
1493 | |||
1324 | return rc; | 1494 | return rc; |
1325 | } | 1495 | } |
1326 | 1496 | ||