summaryrefslogtreecommitdiffstats
path: root/drivers/media/common/tuners/xc4000.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/common/tuners/xc4000.c')
-rw-r--r--drivers/media/common/tuners/xc4000.c191
1 files changed, 129 insertions, 62 deletions
diff --git a/drivers/media/common/tuners/xc4000.c b/drivers/media/common/tuners/xc4000.c
index 634f4d9..6839711 100644
--- a/drivers/media/common/tuners/xc4000.c
+++ b/drivers/media/common/tuners/xc4000.c
@@ -154,6 +154,8 @@ struct xc4000_priv {
#define XREG_SNR 0x06
#define XREG_VERSION 0x07
#define XREG_PRODUCT_ID 0x08
+#define XREG_SIGNAL_LEVEL 0x0A
+#define XREG_NOISE_LEVEL 0x0B
/*
Basic firmware description. This will remain with
@@ -486,6 +488,16 @@ static int xc_get_quality(struct xc4000_priv *priv, u16 *quality)
return xc4000_readreg(priv, XREG_QUALITY, quality);
}
+static int xc_get_signal_level(struct xc4000_priv *priv, u16 *signal)
+{
+ return xc4000_readreg(priv, XREG_SIGNAL_LEVEL, signal);
+}
+
+static int xc_get_noise_level(struct xc4000_priv *priv, u16 *noise)
+{
+ return xc4000_readreg(priv, XREG_NOISE_LEVEL, noise);
+}
+
static u16 xc_wait_for_lock(struct xc4000_priv *priv)
{
u16 lock_state = 0;
@@ -758,7 +770,7 @@ static int xc4000_fwupload(struct dvb_frontend *fe)
n_array, fname, name,
priv->firm_version >> 8, priv->firm_version & 0xff);
- priv->firm = kzalloc(sizeof(*priv->firm) * n_array, GFP_KERNEL);
+ priv->firm = kcalloc(n_array, sizeof(*priv->firm), GFP_KERNEL);
if (priv->firm == NULL) {
printk(KERN_ERR "Not enough memory to load firmware file.\n");
rc = -ENOMEM;
@@ -1089,6 +1101,8 @@ static void xc_debug_dump(struct xc4000_priv *priv)
u32 hsync_freq_hz = 0;
u16 frame_lines;
u16 quality;
+ u16 signal = 0;
+ u16 noise = 0;
u8 hw_majorversion = 0, hw_minorversion = 0;
u8 fw_majorversion = 0, fw_minorversion = 0;
@@ -1119,85 +1133,70 @@ static void xc_debug_dump(struct xc4000_priv *priv)
xc_get_quality(priv, &quality);
dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality);
+
+ xc_get_signal_level(priv, &signal);
+ dprintk(1, "*** Signal level = -%ddB (%d)\n", signal >> 8, signal);
+
+ xc_get_noise_level(priv, &noise);
+ dprintk(1, "*** Noise level = %ddB (%d)\n", noise >> 8, noise);
}
-static int xc4000_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
+static int xc4000_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ u32 delsys = c->delivery_system;
+ u32 bw = c->bandwidth_hz;
struct xc4000_priv *priv = fe->tuner_priv;
unsigned int type;
int ret = -EREMOTEIO;
- dprintk(1, "%s() frequency=%d (Hz)\n", __func__, params->frequency);
+ dprintk(1, "%s() frequency=%d (Hz)\n", __func__, c->frequency);
mutex_lock(&priv->lock);
- if (fe->ops.info.type == FE_ATSC) {
- dprintk(1, "%s() ATSC\n", __func__);
- switch (params->u.vsb.modulation) {
- case VSB_8:
- case VSB_16:
- dprintk(1, "%s() VSB modulation\n", __func__);
- priv->rf_mode = XC_RF_MODE_AIR;
- priv->freq_hz = params->frequency - 1750000;
- priv->bandwidth = BANDWIDTH_6_MHZ;
- priv->video_standard = XC4000_DTV6;
- type = DTV6;
- break;
- case QAM_64:
- case QAM_256:
- case QAM_AUTO:
- dprintk(1, "%s() QAM modulation\n", __func__);
- priv->rf_mode = XC_RF_MODE_CABLE;
- priv->freq_hz = params->frequency - 1750000;
- priv->bandwidth = BANDWIDTH_6_MHZ;
- priv->video_standard = XC4000_DTV6;
- type = DTV6;
- break;
- default:
- ret = -EINVAL;
- goto fail;
- }
- } else if (fe->ops.info.type == FE_OFDM) {
+ switch (delsys) {
+ case SYS_ATSC:
+ dprintk(1, "%s() VSB modulation\n", __func__);
+ priv->rf_mode = XC_RF_MODE_AIR;
+ priv->freq_hz = c->frequency - 1750000;
+ priv->video_standard = XC4000_DTV6;
+ type = DTV6;
+ break;
+ case SYS_DVBC_ANNEX_B:
+ dprintk(1, "%s() QAM modulation\n", __func__);
+ priv->rf_mode = XC_RF_MODE_CABLE;
+ priv->freq_hz = c->frequency - 1750000;
+ priv->video_standard = XC4000_DTV6;
+ type = DTV6;
+ break;
+ case SYS_DVBT:
+ case SYS_DVBT2:
dprintk(1, "%s() OFDM\n", __func__);
- switch (params->u.ofdm.bandwidth) {
- case BANDWIDTH_6_MHZ:
- priv->bandwidth = BANDWIDTH_6_MHZ;
+ if (bw == 0) {
+ if (c->frequency < 400000000) {
+ priv->freq_hz = c->frequency - 2250000;
+ } else {
+ priv->freq_hz = c->frequency - 2750000;
+ }
+ priv->video_standard = XC4000_DTV7_8;
+ type = DTV78;
+ } else if (bw <= 6000000) {
priv->video_standard = XC4000_DTV6;
- priv->freq_hz = params->frequency - 1750000;
+ priv->freq_hz = c->frequency - 1750000;
type = DTV6;
- break;
- case BANDWIDTH_7_MHZ:
- priv->bandwidth = BANDWIDTH_7_MHZ;
+ } else if (bw <= 7000000) {
priv->video_standard = XC4000_DTV7;
- priv->freq_hz = params->frequency - 2250000;
+ priv->freq_hz = c->frequency - 2250000;
type = DTV7;
- break;
- case BANDWIDTH_8_MHZ:
- priv->bandwidth = BANDWIDTH_8_MHZ;
+ } else {
priv->video_standard = XC4000_DTV8;
- priv->freq_hz = params->frequency - 2750000;
+ priv->freq_hz = c->frequency - 2750000;
type = DTV8;
- break;
- case BANDWIDTH_AUTO:
- if (params->frequency < 400000000) {
- priv->bandwidth = BANDWIDTH_7_MHZ;
- priv->freq_hz = params->frequency - 2250000;
- } else {
- priv->bandwidth = BANDWIDTH_8_MHZ;
- priv->freq_hz = params->frequency - 2750000;
- }
- priv->video_standard = XC4000_DTV7_8;
- type = DTV78;
- break;
- default:
- printk(KERN_ERR "xc4000 bandwidth not set!\n");
- ret = -EINVAL;
- goto fail;
}
priv->rf_mode = XC_RF_MODE_AIR;
- } else {
- printk(KERN_ERR "xc4000 modulation type not supported!\n");
+ break;
+ default:
+ printk(KERN_ERR "xc4000 delivery system not supported!\n");
ret = -EINVAL;
goto fail;
}
@@ -1209,6 +1208,8 @@ static int xc4000_set_params(struct dvb_frontend *fe,
if (check_firmware(fe, type, 0, priv->if_khz) != 0)
goto fail;
+ priv->bandwidth = c->bandwidth_hz;
+
ret = xc_set_signal_source(priv, priv->rf_mode);
if (ret != 0) {
printk(KERN_ERR "xc4000: xc_set_signal_source(%d) failed\n",
@@ -1451,6 +1452,71 @@ fail:
return ret;
}
+static int xc4000_get_signal(struct dvb_frontend *fe, u16 *strength)
+{
+ struct xc4000_priv *priv = fe->tuner_priv;
+ u16 value = 0;
+ int rc;
+
+ mutex_lock(&priv->lock);
+ rc = xc4000_readreg(priv, XREG_SIGNAL_LEVEL, &value);
+ mutex_unlock(&priv->lock);
+
+ if (rc < 0)
+ goto ret;
+
+ /* Informations from real testing of DVB-T and radio part,
+ coeficient for one dB is 0xff.
+ */
+ tuner_dbg("Signal strength: -%ddB (%05d)\n", value >> 8, value);
+
+ /* all known digital modes */
+ if ((priv->video_standard == XC4000_DTV6) ||
+ (priv->video_standard == XC4000_DTV7) ||
+ (priv->video_standard == XC4000_DTV7_8) ||
+ (priv->video_standard == XC4000_DTV8))
+ goto digital;
+
+ /* Analog mode has NOISE LEVEL important, signal
+ depends only on gain of antenna and amplifiers,
+ but it doesn't tell anything about real quality
+ of reception.
+ */
+ mutex_lock(&priv->lock);
+ rc = xc4000_readreg(priv, XREG_NOISE_LEVEL, &value);
+ mutex_unlock(&priv->lock);
+
+ tuner_dbg("Noise level: %ddB (%05d)\n", value >> 8, value);
+
+ /* highest noise level: 32dB */
+ if (value >= 0x2000) {
+ value = 0;
+ } else {
+ value = ~value << 3;
+ }
+
+ goto ret;
+
+ /* Digital mode has SIGNAL LEVEL important and real
+ noise level is stored in demodulator registers.
+ */
+digital:
+ /* best signal: -50dB */
+ if (value <= 0x3200) {
+ value = 0xffff;
+ /* minimum: -114dB - should be 0x7200 but real zero is 0x713A */
+ } else if (value >= 0x713A) {
+ value = 0;
+ } else {
+ value = ~(value - 0x3200) << 2;
+ }
+
+ret:
+ *strength = value;
+
+ return rc;
+}
+
static int xc4000_get_frequency(struct dvb_frontend *fe, u32 *freq)
{
struct xc4000_priv *priv = fe->tuner_priv;
@@ -1578,6 +1644,7 @@ static const struct dvb_tuner_ops xc4000_tuner_ops = {
.set_params = xc4000_set_params,
.set_analog_params = xc4000_set_analog_params,
.get_frequency = xc4000_get_frequency,
+ .get_rf_strength = xc4000_get_signal,
.get_bandwidth = xc4000_get_bandwidth,
.get_status = xc4000_get_status
};
@@ -1605,7 +1672,7 @@ struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe,
break;
case 1:
/* new tuner instance */
- priv->bandwidth = BANDWIDTH_6_MHZ;
+ priv->bandwidth = 6000000;
/* set default configuration */
priv->if_khz = 4560;
priv->default_pm = 0;
OpenPOWER on IntegriCloud