diff options
-rw-r--r-- | drivers/media/video/tuner-xc2028-types.h | 3 | ||||
-rw-r--r-- | drivers/media/video/tuner-xc2028.c | 88 | ||||
-rw-r--r-- | drivers/media/video/tuner-xc2028.h | 26 |
3 files changed, 66 insertions, 51 deletions
diff --git a/drivers/media/video/tuner-xc2028-types.h b/drivers/media/video/tuner-xc2028-types.h index c0dc6ec19f0..d0057fbf0ec 100644 --- a/drivers/media/video/tuner-xc2028-types.h +++ b/drivers/media/video/tuner-xc2028-types.h @@ -82,6 +82,9 @@ #define INPUT2 (1 << 28) #define SCODE (1 << 29) +/* This flag identifies that the scode table has a new format */ +#define HAS_IF (1 << 30) + #define SCODE_TYPES (MTS|DTV6|QAM|DTV7|DTV78|DTV8|LCD|NOGD|MONO|ATSC|IF| \ LG60|ATI638|OREN538|OREN36|TOYOTA388|TOYOTA794| \ DIBCOM52|ZARLINK456|CHINA|F6MHZ|SCODE) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index 9743331c895..cf72f22986a 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -50,6 +50,7 @@ static DEFINE_MUTEX(xc2028_list_mutex); struct firmware_description { unsigned int type; v4l2_std_id id; + __u16 int_freq; unsigned char *ptr; unsigned int size; }; @@ -58,6 +59,7 @@ struct firmware_properties { unsigned int type; v4l2_std_id id; v4l2_std_id std_req; + __u16 int_freq; unsigned int scode_table; int scode_nr; }; @@ -301,6 +303,7 @@ static int load_all_firmwares(struct dvb_frontend *fe) while (p < endp) { __u32 type, size; v4l2_std_id id; + __u16 int_freq = 0; n++; if (n >= n_array) { @@ -321,6 +324,11 @@ static int load_all_firmwares(struct dvb_frontend *fe) 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); @@ -351,6 +359,7 @@ static int load_all_firmwares(struct dvb_frontend *fe) priv->firm[n].type = type; priv->firm[n].id = id; priv->firm[n].size = size; + priv->firm[n].int_freq = int_freq; p += size; } @@ -565,7 +574,7 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type, } 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; @@ -573,17 +582,34 @@ static int load_scode(struct dvb_frontend *fe, unsigned int type, 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); @@ -597,7 +623,7 @@ static int load_scode(struct dvb_frontend *fe, unsigned int 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; @@ -609,7 +635,7 @@ static int load_scode(struct dvb_frontend *fe, unsigned int type, } 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; @@ -639,6 +665,7 @@ retry: 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) { @@ -719,8 +746,8 @@ skip_std_specific: /* 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 || @@ -810,9 +837,10 @@ ret: #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; @@ -825,7 +853,7 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */, 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 @@ -896,7 +924,7 @@ static int xc2028_set_analog_freq(struct dvb_frontend *fe, 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 */ @@ -911,22 +939,9 @@ static int xc2028_set_analog_freq(struct dvb_frontend *fe, 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) { @@ -978,13 +993,12 @@ static int xc2028_set_params(struct dvb_frontend *fe, 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) diff --git a/drivers/media/video/tuner-xc2028.h b/drivers/media/video/tuner-xc2028.h index 9b4224e2fe5..1fe8b195960 100644 --- a/drivers/media/video/tuner-xc2028.h +++ b/drivers/media/video/tuner-xc2028.h @@ -11,19 +11,17 @@ #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; @@ -32,7 +30,7 @@ struct xc2028_ctrl { unsigned int mts :1; unsigned int d2633 :1; unsigned int input1:1; - enum xc2028_demod_types demod; + unsigned int demod; }; struct xc2028_config { |