Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4216be14 authored by Mauro Carvalho Chehab's avatar Mauro Carvalho Chehab
Browse files

[media] cxd2841er: fix BER report via DVBv5 stats API



What userspace expects is to receive both bit_error and bit_count
counters. So, instead of doing the division at the Kernel,
return the counters for userspace to handle it the way it
wants.

Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@s-opensource.com>
parent eca2d34b
Loading
Loading
Loading
Loading
+66 −71
Original line number Diff line number Diff line
@@ -1330,11 +1330,10 @@ static int cxd2841er_read_packet_errors_i(
	return 0;
}

static int cxd2841er_mon_read_ber_s(struct cxd2841er_priv *priv, u32 *ber)
static int cxd2841er_mon_read_ber_s(struct cxd2841er_priv *priv,
				    u32 *bit_error, u32 *bit_count)
{
	u8 data[11];
	u32 bit_error, bit_count;
	u32 temp_q, temp_r;

	/* Set SLV-T Bank : 0xA0 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xa0);
@@ -1350,28 +1349,18 @@ static int cxd2841er_mon_read_ber_s(struct cxd2841er_priv *priv, u32 *ber)
	 */
	cxd2841er_read_regs(priv, I2C_SLVT, 0x35, data, 11);
	if (data[0] & 0x01) {
		bit_error = ((u32)(data[1]  & 0x3F) << 16) |
		*bit_error = ((u32)(data[1]  & 0x3F) << 16) |
			     ((u32)(data[2]  & 0xFF) <<  8) |
			     (u32)(data[3]  & 0xFF);
		bit_count = ((u32)(data[8]  & 0x3F) << 16) |
		*bit_count = ((u32)(data[8]  & 0x3F) << 16) |
			     ((u32)(data[9]  & 0xFF) <<  8) |
			     (u32)(data[10] & 0xFF);
		/*
		 *	BER = bitError / bitCount
		 *	= (bitError * 10^7) / bitCount
		 *	= ((bitError * 625 * 125 * 128) / bitCount
		 */
		if ((bit_count == 0) || (bit_error > bit_count)) {
		if ((*bit_count == 0) || (*bit_error > *bit_count)) {
			dev_dbg(&priv->i2c->dev,
				"%s(): invalid bit_error %d, bit_count %d\n",
				__func__, bit_error, bit_count);
				__func__, *bit_error, *bit_count);
			return -EINVAL;
		}
		temp_q = div_u64_rem(10000000ULL * bit_error,
						bit_count, &temp_r);
		if (bit_count != 1 && temp_r >= bit_count / 2)
			temp_q++;
		*ber = temp_q;
		return 0;
	}
	dev_dbg(&priv->i2c->dev, "%s(): no data available\n", __func__);
@@ -1379,11 +1368,11 @@ static int cxd2841er_mon_read_ber_s(struct cxd2841er_priv *priv, u32 *ber)
}


static int cxd2841er_mon_read_ber_s2(struct cxd2841er_priv *priv, u32 *ber)
static int cxd2841er_mon_read_ber_s2(struct cxd2841er_priv *priv,
				     u32 *bit_error, u32 *bit_count)
{
	u8 data[5];
	u32 bit_error, period;
	u32 temp_q, temp_r;
	u32 period;

	/* Set SLV-T Bank : 0xB2 */
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xb2);
@@ -1398,7 +1387,7 @@ static int cxd2841er_mon_read_ber_s2(struct cxd2841er_priv *priv, u32 *ber)
	cxd2841er_read_regs(priv, I2C_SLVT, 0x30, data, 5);
	if (data[0] & 0x01) {
		/* Bit error count */
		bit_error = ((u32)(data[1] & 0x0F) << 24) |
		*bit_error = ((u32)(data[1] & 0x0F) << 24) |
			     ((u32)(data[2] & 0xFF) << 16) |
			     ((u32)(data[3] & 0xFF) <<  8) |
			     (u32)(data[4] & 0xFF);
@@ -1413,24 +1402,14 @@ static int cxd2841er_mon_read_ber_s2(struct cxd2841er_priv *priv, u32 *ber)
				"%s(): period is 0\n", __func__);
			return -EINVAL;
		}
		if (bit_error > (period * 64800)) {
		if (*bit_error > (period * 64800)) {
			dev_dbg(&priv->i2c->dev,
				"%s(): invalid bit_err 0x%x period 0x%x\n",
				__func__, bit_error, period);
				__func__, *bit_error, period);
			return -EINVAL;
		}
		/*
		 * BER = bitError / (period * 64800)
		 *	= (bitError * 10^7) / (period * 64800)
		 *	= (bitError * 10^5) / (period * 648)
		 *	= (bitError * 12500) / (period * 81)
		 *	= (bitError * 10) * 1250 / (period * 81)
		 */
		temp_q = div_u64_rem(12500ULL * bit_error,
					period * 81, &temp_r);
		if (temp_r >= period * 40)
			temp_q++;
		*ber = temp_q;
		*bit_count = period * 64800;

		return 0;
	} else {
		dev_dbg(&priv->i2c->dev,
@@ -1439,13 +1418,12 @@ static int cxd2841er_mon_read_ber_s2(struct cxd2841er_priv *priv, u32 *ber)
	return -EINVAL;
}

static int cxd2841er_read_ber_t2(struct cxd2841er_priv *priv, u32 *ber)
static int cxd2841er_read_ber_t2(struct cxd2841er_priv *priv,
				 u32 *bit_error, u32 *bit_count)
{
	u8 data[4];
	u32 div, q, r;
	u32 bit_err, period_exp, n_ldpc;
	u32 period_exp, n_ldpc;

	*ber = 0;
	if (priv->state != STATE_ACTIVE_TC) {
		dev_dbg(&priv->i2c->dev,
			"%s(): invalid state %d\n", __func__, priv->state);
@@ -1456,9 +1434,9 @@ static int cxd2841er_read_ber_t2(struct cxd2841er_priv *priv, u32 *ber)
	if (!(data[0] & 0x10)) {
		dev_dbg(&priv->i2c->dev,
			"%s(): no valid BER data\n", __func__);
		return 0;
		return -EINVAL;
	}
	bit_err = ((u32)(data[0] & 0x0f) << 24) |
	*bit_error = ((u32)(data[0] & 0x0f) << 24) |
		     ((u32)data[1] << 16) |
		     ((u32)data[2] << 8) |
		     (u32)data[3];
@@ -1467,29 +1445,33 @@ static int cxd2841er_read_ber_t2(struct cxd2841er_priv *priv, u32 *ber)
	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x22);
	cxd2841er_read_reg(priv, I2C_SLVT, 0x5e, data);
	n_ldpc = ((data[0] & 0x03) == 0 ? 16200 : 64800);
	if (bit_err > ((1U << period_exp) * n_ldpc)) {
	if (*bit_error > ((1U << period_exp) * n_ldpc)) {
		dev_dbg(&priv->i2c->dev,
			"%s(): invalid BER value\n", __func__);
		return -EINVAL;
	}

	/*
	 * FIXME: the right thing would be to return bit_error untouched,
	 * but, as we don't know the scale returned by the counters, let's
	 * at least preserver BER = bit_error/bit_count.
	 */
	if (period_exp >= 4) {
		div = (1U << (period_exp - 4)) * (n_ldpc / 200);
		q = div_u64_rem(3125ULL * bit_err, div, &r);
		*bit_count = (1U << (period_exp - 4)) * (n_ldpc / 200);
		*bit_error *= 3125ULL;
	} else {
		div = (1U << period_exp) * (n_ldpc / 200);
		q = div_u64_rem(50000ULL * bit_err, div, &r);
		*bit_count = (1U << period_exp) * (n_ldpc / 200);
		*bit_error *= 50000ULL;;
	}
	*ber = (r >= div / 2) ? q + 1 : q;
	return 0;
}

static int cxd2841er_read_ber_t(struct cxd2841er_priv *priv, u32 *ber)
static int cxd2841er_read_ber_t(struct cxd2841er_priv *priv,
				u32 *bit_error, u32 *bit_count)
{
	u8 data[2];
	u32 div, q, r;
	u32 bit_err, period;
	u32 period;

	*ber = 0;
	if (priv->state != STATE_ACTIVE_TC) {
		dev_dbg(&priv->i2c->dev,
			"%s(): invalid state %d\n", __func__, priv->state);
@@ -1503,12 +1485,17 @@ static int cxd2841er_read_ber_t(struct cxd2841er_priv *priv, u32 *ber)
		return 0;
	}
	cxd2841er_read_regs(priv, I2C_SLVT, 0x22, data, sizeof(data));
	bit_err = ((u32)data[0] << 8) | (u32)data[1];
	*bit_error = ((u32)data[0] << 8) | (u32)data[1];
	cxd2841er_read_reg(priv, I2C_SLVT, 0x6f, data);
	period = ((data[0] & 0x07) == 0) ? 256 : (4096 << (data[0] & 0x07));
	div = period / 128;
	q = div_u64_rem(78125ULL * bit_err, div, &r);
	*ber = (r >= div / 2) ? q + 1 : q;

	/*
	 * FIXME: the right thing would be to return bit_error untouched,
	 * but, as we don't know the scale returned by the counters, let's
	 * at least preserver BER = bit_error/bit_count.
	 */
	*bit_count = period / 128;
	*bit_error *= 78125ULL;
	return 0;
}

@@ -1722,32 +1709,36 @@ static void cxd2841er_read_ber(struct dvb_frontend *fe)
{
	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
	struct cxd2841er_priv *priv = fe->demodulator_priv;
	u32 ber = 0, ret;
	u32 ret, bit_error = 0, bit_count = 0;

	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
	switch (p->delivery_system) {
	case SYS_DVBS:
		ret = cxd2841er_mon_read_ber_s(priv, &ber);
		ret = cxd2841er_mon_read_ber_s(priv, &bit_error, &bit_count);
		break;
	case SYS_DVBS2:
		ret = cxd2841er_mon_read_ber_s2(priv, &ber);
		ret = cxd2841er_mon_read_ber_s2(priv, &bit_error, &bit_count);
		break;
	case SYS_DVBT:
		ret = cxd2841er_read_ber_t(priv, &ber);
		ret = cxd2841er_read_ber_t(priv, &bit_error, &bit_count);
		break;
	case SYS_DVBT2:
		ret = cxd2841er_read_ber_t2(priv, &ber);
		ret = cxd2841er_read_ber_t2(priv, &bit_error, &bit_count);
		break;
	default:
		p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
		p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
		return;
	}

	if (!ret) {
		p->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
		p->post_bit_error.stat[0].uvalue = ber;
		p->post_bit_error.stat[0].uvalue = bit_error;
		p->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
		p->post_bit_count.stat[0].uvalue = bit_count;
	} else {
		p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
		p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
	}
}

@@ -2988,6 +2979,7 @@ static int cxd2841er_get_frontend(struct dvb_frontend *fe,
		p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
		p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
		p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
		p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
	}
	return 0;
}
@@ -3052,6 +3044,7 @@ static int cxd2841er_set_frontend_s(struct dvb_frontend *fe)
	p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
	p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
	p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
	p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;

	return ret;
}
@@ -3426,6 +3419,8 @@ static void cxd2841er_init_stats(struct dvb_frontend *fe)
	p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
	p->post_bit_error.len = 1;
	p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
	p->post_bit_count.len = 1;
	p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
}