struct firmware_description {
unsigned int type;
v4l2_std_id id;
+ __u16 int_freq;
unsigned char *ptr;
unsigned int size;
};
unsigned int type;
v4l2_std_id id;
v4l2_std_id std_req;
+ __u16 int_freq;
unsigned int scode_table;
int scode_nr;
};
while (p < endp) {
__u32 type, size;
v4l2_std_id id;
+ __u16 int_freq = 0;
n++;
if (n >= n_array) {
id = le64_to_cpu(*(v4l2_std_id *) p);
p += sizeof(id);
+ if (type & HAS_IF) {
+ int_freq = le16_to_cpu(*(__u16 *) p);
+ p += sizeof(int_freq);
+ }
+
size = le32_to_cpu(*(__u32 *) p);
p += sizeof(size);
priv->firm[n].type = type;
priv->firm[n].id = id;
priv->firm[n].size = size;
+ priv->firm[n].int_freq = int_freq;
p += size;
}
}
static int load_scode(struct dvb_frontend *fe, unsigned int type,
- v4l2_std_id *id, int scode)
+ v4l2_std_id *id, __u16 int_freq, int scode)
{
struct xc2028_data *priv = fe->tuner_priv;
int pos, rc;
tuner_dbg("%s called\n", __FUNCTION__);
- pos = seek_firmware(fe, type, id);
- if (pos < 0)
- return pos;
+ if (!int_freq) {
+ pos = seek_firmware(fe, type, id);
+ if (pos < 0)
+ return pos;
+ } else {
+ for (pos = 0; pos < priv->firm_size; pos++) {
+ if ((priv->firm[pos].int_freq == int_freq) &&
+ (type & HAS_IF))
+ break;
+ }
+ if (pos == priv->firm_size)
+ return -ENOENT;
+ }
p = priv->firm[pos].ptr;
- /* 16 SCODE entries per file; each SCODE entry is 12 bytes and
- * has a 2-byte size header in the firmware format. */
- if (priv->firm[pos].size != 14 * 16 || scode >= 16 ||
- le16_to_cpu(*(__u16 *)(p + 14 * scode)) != 12)
- return -EINVAL;
+ if (type & HAS_IF) {
+ if (priv->firm[pos].size != 12 * 16 || scode >= 16)
+ return -EINVAL;
+ p += 12 * scode;
+ } else {
+ /* 16 SCODE entries per file; each SCODE entry is 12 bytes and
+ * has a 2-byte size header in the firmware format. */
+ if (priv->firm[pos].size != 14 * 16 || scode >= 16 ||
+ le16_to_cpu(*(__u16 *)(p + 14 * scode)) != 12)
+ return -EINVAL;
+ p += 14 * scode + 2;
+ }
tuner_info("Loading SCODE for type=");
dump_firm_type(priv->firm[pos].type);
if (rc < 0)
return -EIO;
- rc = i2c_send(priv, p + 14 * scode + 2, 12);
+ rc = i2c_send(priv, p, 12);
if (rc < 0)
return -EIO;
}
static int check_firmware(struct dvb_frontend *fe, unsigned int type,
- v4l2_std_id std)
+ v4l2_std_id std, __u16 int_freq)
{
struct xc2028_data *priv = fe->tuner_priv;
struct firmware_properties new_fw;
new_fw.std_req = std;
new_fw.scode_table = SCODE | priv->ctrl.scode_table;
new_fw.scode_nr = 0;
+ new_fw.int_freq = int_freq;
tuner_dbg("checking firmware, user requested type=");
if (debug) {
/* Load SCODE firmware, if exists */
tuner_dbg("Trying to load scode %d\n", new_fw.scode_nr);
- rc = load_scode(fe, new_fw.type | new_fw.scode_table,
- &new_fw.id, new_fw.scode_nr);
+ rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id,
+ new_fw.int_freq, new_fw.scode_nr);
check_device:
if (xc2028_get_reg(priv, 0x0004, &version) < 0 ||
#define DIV 15625
static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
- enum tuner_mode new_mode,
- unsigned int type,
- v4l2_std_id std)
+ enum tuner_mode new_mode,
+ unsigned int type,
+ v4l2_std_id std,
+ u16 int_freq)
{
struct xc2028_data *priv = fe->tuner_priv;
int rc = -EINVAL;
tuner_dbg("should set frequency %d kHz\n", freq / 1000);
- if (check_firmware(fe, type, std) < 0)
+ if (check_firmware(fe, type, std, int_freq) < 0)
goto ret;
/* On some cases xc2028 can disable video output, if
if (priv->ctrl.input1)
type |= INPUT1;
return generic_set_freq(fe, (625l * p->frequency) / 10,
- T_ANALOG_TV, type, 0);
+ T_ANALOG_TV, type, 0, 0);
}
/* if std is not defined, choose one */
p->std |= parse_audio_std_option();
return generic_set_freq(fe, 62500l * p->frequency,
- T_ANALOG_TV, type, p->std);
+ T_ANALOG_TV, type, p->std, 0);
}
-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)
{
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];
+ /* All S-code tables need a 200kHz shift */
+ if (priv->ctrl.demod)
+ priv->ctrl.demod += 200;
return generic_set_freq(fe, p->frequency,
- T_DIGITAL_TV, type, 0);
+ T_DIGITAL_TV, type, 0, priv->ctrl.demod);
}
static int xc2028_sleep(struct dvb_frontend *fe)
#define XC2028_DEFAULT_FIRMWARE "xc3028-v27.fw"
-enum xc2028_demod_types
-{
- XC3028_FE_DEFAULT = 0,
- XC3028_FE_LG60, /* IF = 6.00 MHz */
- XC3028_FE_ATI638, /* IF = 6.38 MHz */
- XC3028_FE_OREN538, /* IF = 5.38 MHz */
- XC3028_FE_OREN36, /* IF = 3.60 MHz */
- XC3028_FE_TOYOTA388, /* IF = 3.88 MHz */
- XC3028_FE_TOYOTA794, /* IF = 7.94 MHz */
- XC3028_FE_DIBCOM52, /* IF = 5.20 MHz */
- XC3028_FE_ZARLINK456, /* IF = 4.56 MHz */
- XC3028_FE_CHINA, /* IF = 5.20 MHz */
-};
+/* Dmoduler IF (kHz) */
+#define XC3028_FE_DEFAULT 0
+#define XC3028_FE_LG60 6000
+#define XC3028_FE_ATI638 6380
+#define XC3028_FE_OREN538 5380
+#define XC3028_FE_OREN36 3600
+#define XC3028_FE_TOYOTA388 3880
+#define XC3028_FE_TOYOTA794 7940
+#define XC3028_FE_DIBCOM52 5200
+#define XC3028_FE_ZARLINK456 4560
+#define XC3028_FE_CHINA 5200
struct xc2028_ctrl {
char *fname;
unsigned int mts :1;
unsigned int d2633 :1;
unsigned int input1:1;
- enum xc2028_demod_types demod;
+ unsigned int demod;
};
struct xc2028_config {