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 {