else if (type & SCODE)
type &= SCODE_TYPES;
else if (type & DTV_TYPES)
- type = type & DTV_TYPES;
+ type &= DTV_TYPES;
+ else if (type & STD_SPECIFIC_TYPES)
+ type &= STD_SPECIFIC_TYPES;
/* Seek for exact match */
for (i = 0; i < priv->firm_size; i++) {
return 0;
}
-static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode,
- v4l2_std_id std, fe_bandwidth_t bandwidth)
+static int check_firmware(struct dvb_frontend *fe, unsigned int type,
+ v4l2_std_id std)
{
- struct xc2028_data *priv = fe->tuner_priv;
- int rc = 0, is_retry = 0;
- unsigned int type = 0;
+ struct xc2028_data *priv = fe->tuner_priv;
struct firmware_properties new_fw;
- u16 version, hwmodel;
+ int rc = 0, is_retry = 0;
+ u16 version, hwmodel;
+ v4l2_std_id std0;
tuner_dbg("%s called\n", __FUNCTION__);
return rc;
}
- if (priv->ctrl.type == XC2028_FIRM_MTS)
+ if (priv->ctrl.mts)
type |= MTS;
- if (bandwidth == BANDWIDTH_7_MHZ || bandwidth == BANDWIDTH_8_MHZ)
- type |= F8MHZ;
-
- /* FIXME: How to load FM and FM|INPUT1 firmwares? */
-
- if (new_mode == T_DIGITAL_TV) {
- if (priv->ctrl.d2633)
- type |= D2633;
- else
- type |= D2620;
-
- switch (bandwidth) {
- case BANDWIDTH_8_MHZ:
- type |= DTV8;
- break;
- case BANDWIDTH_7_MHZ:
- type |= DTV7;
- break;
- case BANDWIDTH_6_MHZ:
- /* FIXME: Should allow select also ATSC */
- type |= DTV6 | QAM;
- break;
- default:
- tuner_err("error: bandwidth not supported.\n");
- };
- }
retry:
new_fw.type = type;
if (rc < 0)
goto fail;
- rc = load_firmware(fe, BASE | new_fw.type, &new_fw.id);
+ /* BASE firmwares are all std0 */
+ std0 = 0;
+ rc = load_firmware(fe, BASE | new_fw.type, &std0);
if (rc < 0) {
tuner_err("Error %d while loading base firmware\n",
rc);
/* Load INIT1, if needed */
tuner_dbg("Load init1 firmware, if exists\n");
- rc = load_firmware(fe, BASE | INIT1 | new_fw.type, &new_fw.id);
+ rc = load_firmware(fe, BASE | INIT1 | new_fw.type, &std0);
+ if (rc == -ENOENT)
+ rc = load_firmware(fe, (BASE | INIT1 | new_fw.type) & ~F8MHZ,
+ &std0);
if (rc < 0 && rc != -ENOENT) {
tuner_err("Error %d while loading init1 firmware\n",
rc);
/* Reloading std-specific firmware forces a SCODE update */
priv->cur_fw.scode_table = 0;
- /* Add audio hack to std mask */
- if (new_mode == T_ANALOG_TV)
- new_fw.id |= parse_audio_std_option();
-
rc = load_firmware(fe, new_fw.type, &new_fw.id);
+ if (rc == -ENOENT)
+ rc = load_firmware(fe, new_fw.type & ~F8MHZ, &new_fw.id);
+
if (rc < 0)
goto fail;
#define DIV 15625
-static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */ ,
+static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
enum tuner_mode new_mode,
- v4l2_std_id std, fe_bandwidth_t bandwidth)
+ unsigned int type,
+ v4l2_std_id std)
{
struct xc2028_data *priv = fe->tuner_priv;
int rc = -EINVAL;
mutex_lock(&priv->lock);
- /* HACK: It seems that specific firmware need to be reloaded
- when watching analog TV and freq is changed */
- if (new_mode != T_DIGITAL_TV)
- priv->cur_fw.type = 0;
-
tuner_dbg("should set frequency %d kHz\n", freq / 1000);
- if (check_firmware(fe, new_mode, std, bandwidth) < 0)
+ if (check_firmware(fe, type, std) < 0)
goto ret;
- if (new_mode == T_DIGITAL_TV) {
+ /* On some cases xc2028 can disable video output, if
+ * very weak signals are received. By sending a soft
+ * reset, this is re-enabled. So, it is better to always
+ * send a soft reset before changing channels, to be sure
+ * that xc2028 will be in a safe state.
+ * Maybe this might also be needed for DTV.
+ */
+ if (new_mode == T_ANALOG_TV) {
+ rc = send_seq(priv, {0x00, 0x00});
+ } else {
offset = 2750000;
if (priv->cur_fw.type & DTV7)
offset -= 500000;
return rc;
}
-static int xc2028_set_tv_freq(struct dvb_frontend *fe,
+static int xc2028_set_analog_freq(struct dvb_frontend *fe,
struct analog_parameters *p)
{
struct xc2028_data *priv = fe->tuner_priv;
+ unsigned int type=0;
tuner_dbg("%s called\n", __FUNCTION__);
- return generic_set_tv_freq(fe, 62500l * p->frequency, T_ANALOG_TV,
- p->std, BANDWIDTH_8_MHZ);
- /* XXX Are some analog standards 6MHz? */
+ if (p->mode == V4L2_TUNER_RADIO) {
+ type |= FM;
+ if (priv->ctrl.input1)
+ type |= INPUT1;
+ return generic_set_freq(fe, (625l * p->frequency) / 10,
+ T_ANALOG_TV, type, 0);
+ }
+
+ /* if std is not defined, choose one */
+ if (!p->std)
+ p->std = V4L2_STD_MN;
+
+ /* PAL/M, PAL/N, PAL/Nc and NTSC variants should use 6MHz firmware */
+ if (!(p->std & V4L2_STD_MN))
+ type |= F8MHZ;
+
+ /* Add audio hack to std mask */
+ p->std |= parse_audio_std_option();
+
+ return generic_set_freq(fe, 62500l * p->frequency,
+ T_ANALOG_TV, type, p->std);
}
+static unsigned int demod_type [] = {
+ [XC3028_FE_DEFAULT] = 0,
+ [XC3028_FE_LG60] = LG60,
+ [XC3028_FE_ATI638] = ATI638,
+ [XC3028_FE_OREN538] = OREN538,
+ [XC3028_FE_OREN36] = OREN36,
+ [XC3028_FE_TOYOTA388] = TOYOTA388,
+ [XC3028_FE_TOYOTA794] = TOYOTA794,
+ [XC3028_FE_DIBCOM52] = DIBCOM52,
+ [XC3028_FE_ZARLINK456] = ZARLINK456,
+ [XC3028_FE_CHINA] = CHINA,
+};
+
static int xc2028_set_params(struct dvb_frontend *fe,
struct dvb_frontend_parameters *p)
{
struct xc2028_data *priv = fe->tuner_priv;
+ unsigned int type=0;
+ fe_bandwidth_t bw = BANDWIDTH_8_MHZ;
tuner_dbg("%s called\n", __FUNCTION__);
- /* FIXME: Only OFDM implemented */
- if (fe->ops.info.type != FE_OFDM) {
- tuner_err("DTV type not implemented.\n");
- return -EINVAL;
+ if (priv->ctrl.d2633)
+ type |= D2633;
+ else
+ type |= D2620;
+
+ switch(fe->ops.info.type) {
+ case FE_QPSK:
+ break;
+ case FE_OFDM:
+ bw = p->u.ofdm.bandwidth;
+ break;
+ case FE_QAM:
+ bw = BANDWIDTH_6_MHZ;
+ type |= QAM;
+ break;
+ case FE_ATSC:
+ bw = BANDWIDTH_6_MHZ;
+ type |= ATSC| D2633;
+ break;
}
- return generic_set_tv_freq(fe, p->frequency, T_DIGITAL_TV,
- 0 /* NOT USED */,
- p->u.ofdm.bandwidth);
+ bw = p->u.ofdm.bandwidth;
+
+ /* FIXME:
+ There are two Scodes that will never be selected:
+ DTV78 ZARLINK456, DTV78 DIBCOM52
+ When it should opt for DTV78 instead of DTV7 or DTV8?
+ */
+ switch (bw) {
+ case BANDWIDTH_8_MHZ:
+ type |= DTV8 | F8MHZ;
+ break;
+ case BANDWIDTH_7_MHZ:
+ type |= DTV7 | F8MHZ;
+ break;
+ case BANDWIDTH_6_MHZ:
+ type |= DTV6 ;
+ break;
+ default:
+ tuner_err("error: bandwidth not supported.\n");
+ };
+
+ if (priv->ctrl.demod < 0 || priv->ctrl.demod > ARRAY_SIZE(demod_type))
+ tuner_err("error: demod type invalid. Assuming default.\n");
+ else
+ type |= demod_type[priv->ctrl.demod];
+ return generic_set_freq(fe, p->frequency,
+ T_DIGITAL_TV, type, 0);
}
+static int xc2028_sleep(struct dvb_frontend *fe)
+{
+ struct xc2028_data *priv = fe->tuner_priv;
+ int rc = 0;
+
+ tuner_dbg("%s called\n", __FUNCTION__);
+
+ mutex_lock(&priv->lock);
+
+ if (priv->firm_version < 0x0202)
+ rc = send_seq(priv, {0x00, 0x08, 0x00, 0x00});
+ else
+ rc = send_seq(priv, {0x80, 0x08, 0x00, 0x00});
+
+ priv->cur_fw.type = 0; /* need firmware reload */
+
+ mutex_unlock(&priv->lock);
+
+ return rc;
+}
+
+
static int xc2028_dvb_release(struct dvb_frontend *fe)
{
struct xc2028_data *priv = fe->tuner_priv;
},
.set_config = xc2028_set_config,
- .set_analog_params = xc2028_set_tv_freq,
+ .set_analog_params = xc2028_set_analog_freq,
.release = xc2028_dvb_release,
.get_frequency = xc2028_get_frequency,
.get_rf_strength = xc2028_signal,
.set_params = xc2028_set_params,
+ .sleep = xc2028_sleep,
};
if (debug)
printk(KERN_DEBUG PREFIX ": Xcv2028/3028 init called!\n");
- if (NULL == cfg->video_dev)
+ if (NULL == cfg || NULL == cfg->video_dev)
return NULL;
if (!fe) {
tuner_info("type set to %s\n", "XCeive xc2028/xc3028 tuner");
+ if (cfg->ctrl)
+ xc2028_set_config(fe, cfg->ctrl);
+
mutex_unlock(&xc2028_list_mutex);
return fe;