Commit 267897a4 authored by Antti Palosaari's avatar Antti Palosaari Committed by Mauro Carvalho Chehab

[media] tda10071: implement DVBv5 statistics

Implement DVBv5 CNR, signal strength, BER and block errors.

Wrap legacy DVBv3 statistics to DVBv5 internally.
Signed-off-by: default avatarAntti Palosaari <crope@iki.fi>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@osg.samsung.com>
parent 4c4acb7a
...@@ -377,8 +377,11 @@ static int tda10071_read_status(struct dvb_frontend *fe, enum fe_status *status) ...@@ -377,8 +377,11 @@ static int tda10071_read_status(struct dvb_frontend *fe, enum fe_status *status)
{ {
struct tda10071_dev *dev = fe->demodulator_priv; struct tda10071_dev *dev = fe->demodulator_priv;
struct i2c_client *client = dev->client; struct i2c_client *client = dev->client;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct tda10071_cmd cmd;
int ret; int ret;
unsigned int uitmp; unsigned int uitmp;
u8 buf[8];
*status = 0; *status = 0;
...@@ -401,52 +404,8 @@ static int tda10071_read_status(struct dvb_frontend *fe, enum fe_status *status) ...@@ -401,52 +404,8 @@ static int tda10071_read_status(struct dvb_frontend *fe, enum fe_status *status)
dev->fe_status = *status; dev->fe_status = *status;
return ret; /* signal strength */
error: if (dev->fe_status & FE_HAS_SIGNAL) {
dev_dbg(&client->dev, "failed=%d\n", ret);
return ret;
}
static int tda10071_read_snr(struct dvb_frontend *fe, u16 *snr)
{
struct tda10071_dev *dev = fe->demodulator_priv;
struct i2c_client *client = dev->client;
int ret;
u8 buf[2];
if (!dev->warm || !(dev->fe_status & FE_HAS_LOCK)) {
*snr = 0;
ret = 0;
goto error;
}
ret = regmap_bulk_read(dev->regmap, 0x3a, buf, 2);
if (ret)
goto error;
/* Es/No dBx10 */
*snr = buf[0] << 8 | buf[1];
return ret;
error:
dev_dbg(&client->dev, "failed=%d\n", ret);
return ret;
}
static int tda10071_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
{
struct tda10071_dev *dev = fe->demodulator_priv;
struct i2c_client *client = dev->client;
struct tda10071_cmd cmd;
int ret;
unsigned int uitmp;
if (!dev->warm || !(dev->fe_status & FE_HAS_LOCK)) {
*strength = 0;
ret = 0;
goto error;
}
cmd.args[0] = CMD_GET_AGCACC; cmd.args[0] = CMD_GET_AGCACC;
cmd.args[1] = 0; cmd.args[1] = 0;
cmd.len = 2; cmd.len = 2;
...@@ -459,66 +418,61 @@ static int tda10071_read_signal_strength(struct dvb_frontend *fe, u16 *strength) ...@@ -459,66 +418,61 @@ static int tda10071_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
if (ret) if (ret)
goto error; goto error;
if (uitmp < 181) c->strength.stat[0].scale = FE_SCALE_DECIBEL;
uitmp = 181; /* -75 dBm */ c->strength.stat[0].svalue = (int) (uitmp - 256) * 1000;
else if (uitmp > 236) } else {
uitmp = 236; /* -20 dBm */ c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
}
/* scale value to 0x0000-0xffff */
*strength = (uitmp-181) * 0xffff / (236-181);
return ret;
error:
dev_dbg(&client->dev, "failed=%d\n", ret);
return ret;
}
static int tda10071_read_ber(struct dvb_frontend *fe, u32 *ber)
{
struct tda10071_dev *dev = fe->demodulator_priv;
struct i2c_client *client = dev->client;
struct tda10071_cmd cmd;
int ret, i, len;
unsigned int uitmp;
u8 reg, buf[8];
if (!dev->warm || !(dev->fe_status & FE_HAS_LOCK)) { /* CNR */
*ber = dev->ber = 0; if (dev->fe_status & FE_HAS_VITERBI) {
ret = 0; /* Es/No */
ret = regmap_bulk_read(dev->regmap, 0x3a, buf, 2);
if (ret)
goto error; goto error;
c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
c->cnr.stat[0].svalue = (buf[0] << 8 | buf[1] << 0) * 100;
} else {
c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
} }
/* UCB/PER/BER */
if (dev->fe_status & FE_HAS_LOCK) {
/* TODO: report total bits/packets */
u8 delivery_system, reg, len;
switch (dev->delivery_system) { switch (dev->delivery_system) {
case SYS_DVBS: case SYS_DVBS:
reg = 0x4c; reg = 0x4c;
len = 8; len = 8;
i = 1; delivery_system = 1;
break; break;
case SYS_DVBS2: case SYS_DVBS2:
reg = 0x4d; reg = 0x4d;
len = 4; len = 4;
i = 0; delivery_system = 0;
break; break;
default: default:
*ber = dev->ber = 0; ret = -EINVAL;
return 0; goto error;
} }
ret = regmap_read(dev->regmap, reg, &uitmp); ret = regmap_read(dev->regmap, reg, &uitmp);
if (ret) if (ret)
goto error; goto error;
if (dev->meas_count[i] == uitmp) { if (dev->meas_count == uitmp) {
dev_dbg(&client->dev, "meas not ready=%02x\n", uitmp); dev_dbg(&client->dev, "meas not ready=%02x\n", uitmp);
*ber = dev->ber; ret = 0;
return 0; goto error;
} else { } else {
dev->meas_count[i] = uitmp; dev->meas_count = uitmp;
} }
cmd.args[0] = CMD_BER_UPDATE_COUNTERS; cmd.args[0] = CMD_BER_UPDATE_COUNTERS;
cmd.args[1] = 0; cmd.args[1] = 0;
cmd.args[2] = i; cmd.args[2] = delivery_system;
cmd.len = 3; cmd.len = 3;
ret = tda10071_cmd_execute(dev, &cmd); ret = tda10071_cmd_execute(dev, &cmd);
if (ret) if (ret)
...@@ -529,12 +483,26 @@ static int tda10071_read_ber(struct dvb_frontend *fe, u32 *ber) ...@@ -529,12 +483,26 @@ static int tda10071_read_ber(struct dvb_frontend *fe, u32 *ber)
goto error; goto error;
if (dev->delivery_system == SYS_DVBS) { if (dev->delivery_system == SYS_DVBS) {
*ber = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; dev->dvbv3_ber = buf[0] << 24 | buf[1] << 16 |
dev->ucb += (buf[4] << 8) | buf[5]; buf[2] << 8 | buf[3] << 0;
dev->post_bit_error += buf[0] << 24 | buf[1] << 16 |
buf[2] << 8 | buf[3] << 0;
c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
c->post_bit_error.stat[0].uvalue = dev->post_bit_error;
dev->block_error += buf[4] << 8 | buf[5] << 0;
c->block_error.stat[0].scale = FE_SCALE_COUNTER;
c->block_error.stat[0].uvalue = dev->block_error;
} else {
dev->dvbv3_ber = buf[0] << 8 | buf[1] << 0;
dev->post_bit_error += buf[0] << 8 | buf[1] << 0;
c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
c->post_bit_error.stat[0].uvalue = dev->post_bit_error;
c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
}
} else { } else {
*ber = (buf[0] << 8) | buf[1]; c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
} }
dev->ber = *ber;
return ret; return ret;
error: error:
...@@ -542,25 +510,50 @@ static int tda10071_read_ber(struct dvb_frontend *fe, u32 *ber) ...@@ -542,25 +510,50 @@ static int tda10071_read_ber(struct dvb_frontend *fe, u32 *ber)
return ret; return ret;
} }
static int tda10071_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) static int tda10071_read_snr(struct dvb_frontend *fe, u16 *snr)
{ {
struct tda10071_dev *dev = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct i2c_client *client = dev->client;
int ret = 0;
if (!dev->warm || !(dev->fe_status & FE_HAS_LOCK)) { if (c->cnr.stat[0].scale == FE_SCALE_DECIBEL)
*ucblocks = 0; *snr = div_s64(c->cnr.stat[0].svalue, 100);
goto error; else
*snr = 0;
return 0;
}
static int tda10071_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
{
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
unsigned int uitmp;
if (c->strength.stat[0].scale == FE_SCALE_DECIBEL) {
uitmp = c->strength.stat[0].svalue / 1000 + 256;
uitmp = clamp(uitmp, 181U, 236U); /* -75dBm - -20dBm */
/* scale value to 0x0000-0xffff */
*strength = (uitmp-181) * 0xffff / (236-181);
} else {
*strength = 0;
} }
return 0;
}
static int tda10071_read_ber(struct dvb_frontend *fe, u32 *ber)
{
struct tda10071_dev *dev = fe->demodulator_priv;
/* UCB is updated when BER is read. Assume BER is read anyway. */ *ber = dev->dvbv3_ber;
return 0;
}
*ucblocks = dev->ucb; static int tda10071_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
{
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
return ret; if (c->block_error.stat[0].scale == FE_SCALE_COUNTER)
error: *ucblocks = c->block_error.stat[0].uvalue;
dev_dbg(&client->dev, "failed=%d\n", ret); else
return ret; *ucblocks = 0;
return 0;
} }
static int tda10071_set_frontend(struct dvb_frontend *fe) static int tda10071_set_frontend(struct dvb_frontend *fe)
...@@ -770,6 +763,7 @@ static int tda10071_init(struct dvb_frontend *fe) ...@@ -770,6 +763,7 @@ static int tda10071_init(struct dvb_frontend *fe)
{ {
struct tda10071_dev *dev = fe->demodulator_priv; struct tda10071_dev *dev = fe->demodulator_priv;
struct i2c_client *client = dev->client; struct i2c_client *client = dev->client;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct tda10071_cmd cmd; struct tda10071_cmd cmd;
int ret, i, len, remaining, fw_size; int ret, i, len, remaining, fw_size;
unsigned int uitmp; unsigned int uitmp;
...@@ -1035,6 +1029,16 @@ static int tda10071_init(struct dvb_frontend *fe) ...@@ -1035,6 +1029,16 @@ static int tda10071_init(struct dvb_frontend *fe)
goto error; goto error;
} }
/* init stats here in order signal app which stats are supported */
c->strength.len = 1;
c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
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->block_error.len = 1;
c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
return ret; return ret;
error_release_firmware: error_release_firmware:
release_firmware(fw); release_firmware(fw);
......
...@@ -38,12 +38,13 @@ struct tda10071_dev { ...@@ -38,12 +38,13 @@ struct tda10071_dev {
u8 pll_multiplier; u8 pll_multiplier;
u8 tuner_i2c_addr; u8 tuner_i2c_addr;
u8 meas_count[2]; u8 meas_count;
u32 ber; u32 dvbv3_ber;
u32 ucb;
enum fe_status fe_status; enum fe_status fe_status;
enum fe_delivery_system delivery_system; enum fe_delivery_system delivery_system;
bool warm; /* FW running */ bool warm; /* FW running */
u64 post_bit_error;
u64 block_error;
}; };
static struct tda10071_modcod { static struct tda10071_modcod {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment