diff options
Diffstat (limited to 'drivers/media/common/tuners/xc4000.c')
-rw-r--r-- | drivers/media/common/tuners/xc4000.c | 191 |
1 files changed, 129 insertions, 62 deletions
diff --git a/drivers/media/common/tuners/xc4000.c b/drivers/media/common/tuners/xc4000.c index 634f4d9b6c6..68397110b7d 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; |