@@ -19,10 +19,11 @@
*/
#include "rtl2832_priv.h"
+#include "rtl28xxu_tuners.h"
-int rtl2832_debug = 1;
+int rtl2832_debug;
module_param_named(debug, rtl2832_debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
@@ -391,6 +392,58 @@ err:
}
+static int rtl2832_wr_i2c(struct rtl2832_priv *priv, u8 addr, u8 reg, u8 *val, int len)
+{
+ int ret;
+ u8 buf[1+len];
+ struct i2c_msg msg[1] = {
+ {
+ .addr = addr,
+ .flags = 0,
+ .len = 1+len,
+ .buf = buf,
+ }
+ };
+
+ buf[0] = reg;
+ memcpy(&buf[1], val, len);
+
+ ret = i2c_transfer(priv->i2c, msg, 1);
+ if (ret == 1) {
+ ret = 0;
+ } else {
+ warn("i2c wr failed=%d reg=%02x len=%d", ret, reg, len);
+ ret = -EREMOTEIO;
+ }
+ return ret;
+}
+
+static int rtl2832_rd_i2c(struct rtl2832_priv *priv, u8 addr, u8 reg, u8 *val, int len)
+{
+ int ret;
+ struct i2c_msg msg[2] = {
+ {
+ .addr = addr,
+ .flags = 0,
+ .len = 1,
+ .buf = ®,
+ }, {
+ .addr = addr,
+ .flags = I2C_M_RD,
+ .len = len,
+ .buf = val,
+ }
+ };
+
+ ret = i2c_transfer(priv->i2c, msg, 2);
+ if (ret == 2) {
+ ret = 0;
+ } else {
+ warn("i2c rd failed=%d reg=%02x len=%d", ret, reg, len);
+ ret = -EREMOTEIO;
+ }
+ return ret;
+}
static int rtl2832_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
{
@@ -683,7 +736,9 @@ static int rtl2832_read_status(struct dv
*status = 0;
+#if 0
info("%s", __func__);
+#endif
if (priv->sleeping)
return 0;
@@ -707,32 +762,198 @@ err:
return ret;
}
+#define RTL2832_CE_EST_EVM_MAX_VALUE 65535
+#define RTL2832_SNR_FRAC_BIT_NUM 10
+#define RTL2832_SNR_DB_DEN 3402
+
static int rtl2832_read_snr(struct dvb_frontend *fe, u16 *snr)
{
- info("%s", __func__);
- *snr = 0;
+ struct rtl2832_priv *priv = fe->demodulator_priv;
+ int ret;
+ u32 fsm_stage, ce_est_evm, constellation, hierarchy;
+ int num;
+ static const int snr_db_num_const[3][4] =
+ {
+ {122880, 122880, 122880, 122880, },
+ {146657, 146657, 156897, 171013, },
+ {167857, 167857, 173127, 181810, },
+ };
+
+ ret = rtl2832_rd_demod_reg(priv, DVBT_FSM_STAGE, &fsm_stage);
+ if (ret)
+ goto err;
+
+ if (fsm_stage < 10)
+ ce_est_evm = RTL2832_CE_EST_EVM_MAX_VALUE;
+ else {
+ ret = rtl2832_rd_demod_reg(priv, DVBT_CE_EST_EVM, &ce_est_evm);
+ if (ret)
+ goto err;
+ }
+
+ ret = rtl2832_rd_demod_reg(priv, DVBT_RX_CONSTEL, &constellation);
+ if (ret)
+ goto err;
+ if (constellation > 2)
+ goto err;
+
+ ret = rtl2832_rd_demod_reg(priv, DVBT_RX_HIER, &hierarchy);
+ if (ret)
+ goto err;
+ if (hierarchy > 3)
+ goto err;
+
+ num = snr_db_num_const[constellation][hierarchy] -
+ 10*ilog2(ce_est_evm*ce_est_evm)*0x200;
+ if (num < 0)
+ *snr = 0;
+ else
+ *snr = 256 * num / RTL2832_SNR_DB_DEN;
return 0;
+
+err:
+ info("%s: failed=%d", __func__, ret);
+ return ret;
}
static int rtl2832_read_ber(struct dvb_frontend *fe, u32 *ber)
{
- info("%s", __func__);
- *ber = 0;
+ struct rtl2832_priv *priv = fe->demodulator_priv;
+ u32 tmp;
+ int ret;
+
+ ret = rtl2832_rd_demod_reg(priv, DVBT_RSD_BER_EST, &tmp);
+ if (ret)
+ goto err;
+ *ber = tmp;
return 0;
+
+err:
+ info("%s: failed=%d", __func__, ret);
+ *ber = 0;
+ return ret;
}
static int rtl2832_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
{
- info("%s", __func__);
*ucblocks = 0;
return 0;
}
-static int rtl2832_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+#define INPUT_ADC_LEVEL -8
+
+const int fc001x_lna_gain_table[] = {
+ /* low gain */
+ -63, -58, -99, -73,
+ -63, -65, -54, -60,
+ /* middle gain */
+ 71, 70, 68, 67,
+ 65, 63, 61, 58,
+ /* high gain */
+ 197, 191, 188, 186,
+ 184, 182, 181, 179,
+};
+
+static int rtl2832_fc001x_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
{
- info("%s", __func__);
+ struct rtl2832_priv *priv = fe->demodulator_priv;
+ int ret;
+ u8 val, reg;
+ int int_temp, lna_gain, int_lna, tot_agc_gain, power;
+
+ if (priv->tuner == TUNER_RTL2832_FC0013)
+ reg = 0x13;
+ else
+ reg = 0x12;
+
+ ret = rtl2832_i2c_gate_ctrl(fe, true);
+ if (ret)
+ goto err;
+
+ val = 0x00;
+ ret = rtl2832_wr_i2c(priv, 0xc6 >> 1, reg, &val, 1);
+ if (ret) {
+ err("%s: rtl2832_wr_i2c failed, ret=%d", __func__, ret);
+ goto err_gate;
+ } else {
+ ret = rtl2832_rd_i2c(priv, 0xc6 >> 1, reg, &val, 1);
+ if (ret)
+ err("%s: rtl2832_rd_i2c failed, ret=%d", __func__, ret);
+// info("fc001x read 0x12: 0x%02x", val);
+ int_temp = val;
+
+ ret = rtl2832_rd_i2c(priv, 0xc6 >> 1, reg + 1, &val, 1);
+ if (ret)
+ err("%s: rtl2832_rd_i2c failed, ret=%d", __func__, ret);
+// info("fc001x read 0x13: 0x%02x", val);
+ lna_gain = val & 0x1f;
+ }
+
+ ret = rtl2832_i2c_gate_ctrl(fe, false);
+ if (ret)
+ goto err;
+
+ if (lna_gain < ARRAY_SIZE(fc001x_lna_gain_table)) {
+ int_lna = fc001x_lna_gain_table[lna_gain];
+ tot_agc_gain = (abs((int_temp >> 5) - 7) -2) * 2 +
+ (int_temp & 0x1f) * 2;
+ power = INPUT_ADC_LEVEL - tot_agc_gain - int_lna / 10;
+
+ if (power >= 45)
+ *strength = 255; /* 100% */
+ else if (power < -95)
+ *strength = 0;
+ else
+ *strength = (power + 95) * 255 / 140;
+ *strength |= *strength << 8;
+ } else {
+ ret = -1;
+ goto err;
+ }
+
+ return 0;
+
+err_gate:
+ ret = rtl2832_i2c_gate_ctrl(fe, false);
+err:
*strength = 0;
+ return ret;
+}
+
+static int rtl2832_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+ struct rtl2832_priv *priv = fe->demodulator_priv;
+ int ret, if_agc;
+ u32 fsm_stage, if_agc_raw;
+
+ if ((priv->tuner == TUNER_RTL2832_FC0012) ||
+ (priv->tuner == TUNER_RTL2832_FC0013))
+ return rtl2832_fc001x_read_signal_strength(fe, strength);
+
+ ret = rtl2832_rd_demod_reg(priv, DVBT_FSM_STAGE, &fsm_stage);
+ if (ret)
+ goto err;
+ if (fsm_stage < 10)
+ *strength = 0;
+ else {
+ /* if_agc is read as a 10bit binary */
+ ret = rtl2832_rd_demod_reg(priv, DVBT_IF_AGC_VAL, &if_agc_raw);
+ if (ret)
+ goto err;
+ info("%s: if_agc_raw: 0x%04x", __func__, if_agc_raw);
+ if (if_agc_raw < (1 << 9))
+ if_agc = if_agc_raw;
+ else {
+ if_agc = -(~(if_agc_raw-1) & 0x1ff);
+ }
+ *strength = 55 - if_agc / 182;
+ *strength |= *strength << 8;
+ }
+
return 0;
+err:
+ info("%s: failed=%d", __func__, ret);
+ return ret;
}
static struct dvb_frontend_ops rtl2832_ops;
@@ -0,0 +1,44 @@
+/*
+ * Realtek RTL28xxU DVB USB driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef RTL28XXU_TUNERS_H
+#define RTL28XXU_TUNERS_H
+
+enum rtl28xxu_tuner {
+ TUNER_NONE,
+
+ TUNER_RTL2830_QT1010,
+ TUNER_RTL2830_MT2060,
+ TUNER_RTL2830_MXL5005S,
+
+ TUNER_RTL2832_MT2266,
+ TUNER_RTL2832_FC2580,
+ TUNER_RTL2832_MT2063,
+ TUNER_RTL2832_MAX3543,
+ TUNER_RTL2832_TUA9001,
+ TUNER_RTL2832_MXL5007T,
+ TUNER_RTL2832_FC0012,
+ TUNER_RTL2832_E4000,
+ TUNER_RTL2832_TDA18272,
+ TUNER_RTL2832_FC0013,
+};
+
+#endif
@@ -84,25 +84,6 @@ enum rtl28xxu_chip_id {
CHIP_ID_RTL2832U,
};
-enum rtl28xxu_tuner {
- TUNER_NONE,
-
- TUNER_RTL2830_QT1010,
- TUNER_RTL2830_MT2060,
- TUNER_RTL2830_MXL5005S,
-
- TUNER_RTL2832_MT2266,
- TUNER_RTL2832_FC2580,
- TUNER_RTL2832_MT2063,
- TUNER_RTL2832_MAX3543,
- TUNER_RTL2832_TUA9001,
- TUNER_RTL2832_MXL5007T,
- TUNER_RTL2832_FC0012,
- TUNER_RTL2832_E4000,
- TUNER_RTL2832_TDA18272,
- TUNER_RTL2832_FC0013,
-};
-
struct rtl28xxu_req {
u16 value;
u16 index;
@@ -21,6 +21,7 @@
*/
#include "rtl28xxu.h"
+#include "rtl28xxu_tuners.h"
#include "rtl2830.h"
#include "rtl2832.h"