summaryrefslogtreecommitdiffstats
path: root/drivers/media/video/tuner-xc2028.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/tuner-xc2028.c')
-rw-r--r--drivers/media/video/tuner-xc2028.c88
1 files changed, 51 insertions, 37 deletions
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)