Commit 66c2d53d authored by Mauro Carvalho Chehab's avatar Mauro Carvalho Chehab

V4L/DVB (6676): Improve s-code support

s-code tables are related to IF frequency used for video demodulation.

The s-codes for analog are automatically loaded, according with video standard.
However, for digital, they will depend on the IF of the demoduler chip. IF of
the demoduler.

Before this patch, only a few IF's where possible to use. This patch allows
selecting any IF defined at firmware file.
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent b542dfdc
...@@ -82,6 +82,9 @@ ...@@ -82,6 +82,9 @@
#define INPUT2 (1 << 28) #define INPUT2 (1 << 28)
#define SCODE (1 << 29) #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| \ #define SCODE_TYPES (MTS|DTV6|QAM|DTV7|DTV78|DTV8|LCD|NOGD|MONO|ATSC|IF| \
LG60|ATI638|OREN538|OREN36|TOYOTA388|TOYOTA794| \ LG60|ATI638|OREN538|OREN36|TOYOTA388|TOYOTA794| \
DIBCOM52|ZARLINK456|CHINA|F6MHZ|SCODE) DIBCOM52|ZARLINK456|CHINA|F6MHZ|SCODE)
......
...@@ -50,6 +50,7 @@ static DEFINE_MUTEX(xc2028_list_mutex); ...@@ -50,6 +50,7 @@ static DEFINE_MUTEX(xc2028_list_mutex);
struct firmware_description { struct firmware_description {
unsigned int type; unsigned int type;
v4l2_std_id id; v4l2_std_id id;
__u16 int_freq;
unsigned char *ptr; unsigned char *ptr;
unsigned int size; unsigned int size;
}; };
...@@ -58,6 +59,7 @@ struct firmware_properties { ...@@ -58,6 +59,7 @@ struct firmware_properties {
unsigned int type; unsigned int type;
v4l2_std_id id; v4l2_std_id id;
v4l2_std_id std_req; v4l2_std_id std_req;
__u16 int_freq;
unsigned int scode_table; unsigned int scode_table;
int scode_nr; int scode_nr;
}; };
...@@ -301,6 +303,7 @@ static int load_all_firmwares(struct dvb_frontend *fe) ...@@ -301,6 +303,7 @@ static int load_all_firmwares(struct dvb_frontend *fe)
while (p < endp) { while (p < endp) {
__u32 type, size; __u32 type, size;
v4l2_std_id id; v4l2_std_id id;
__u16 int_freq = 0;
n++; n++;
if (n >= n_array) { if (n >= n_array) {
...@@ -321,6 +324,11 @@ static int load_all_firmwares(struct dvb_frontend *fe) ...@@ -321,6 +324,11 @@ static int load_all_firmwares(struct dvb_frontend *fe)
id = le64_to_cpu(*(v4l2_std_id *) p); id = le64_to_cpu(*(v4l2_std_id *) p);
p += sizeof(id); p += sizeof(id);
if (type & HAS_IF) {
int_freq = le16_to_cpu(*(__u16 *) p);
p += sizeof(int_freq);
}
size = le32_to_cpu(*(__u32 *) p); size = le32_to_cpu(*(__u32 *) p);
p += sizeof(size); p += sizeof(size);
...@@ -351,6 +359,7 @@ static int load_all_firmwares(struct dvb_frontend *fe) ...@@ -351,6 +359,7 @@ static int load_all_firmwares(struct dvb_frontend *fe)
priv->firm[n].type = type; priv->firm[n].type = type;
priv->firm[n].id = id; priv->firm[n].id = id;
priv->firm[n].size = size; priv->firm[n].size = size;
priv->firm[n].int_freq = int_freq;
p += size; p += size;
} }
...@@ -565,7 +574,7 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type, ...@@ -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, 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; struct xc2028_data *priv = fe->tuner_priv;
int pos, rc; int pos, rc;
...@@ -573,17 +582,34 @@ static int load_scode(struct dvb_frontend *fe, unsigned int type, ...@@ -573,17 +582,34 @@ static int load_scode(struct dvb_frontend *fe, unsigned int type,
tuner_dbg("%s called\n", __FUNCTION__); tuner_dbg("%s called\n", __FUNCTION__);
pos = seek_firmware(fe, type, id); if (!int_freq) {
if (pos < 0) pos = seek_firmware(fe, type, id);
return pos; 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; p = priv->firm[pos].ptr;
/* 16 SCODE entries per file; each SCODE entry is 12 bytes and if (type & HAS_IF) {
* has a 2-byte size header in the firmware format. */ if (priv->firm[pos].size != 12 * 16 || scode >= 16)
if (priv->firm[pos].size != 14 * 16 || scode >= 16 || return -EINVAL;
le16_to_cpu(*(__u16 *)(p + 14 * scode)) != 12) p += 12 * scode;
return -EINVAL; } 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="); tuner_info("Loading SCODE for type=");
dump_firm_type(priv->firm[pos].type); dump_firm_type(priv->firm[pos].type);
...@@ -597,7 +623,7 @@ static int load_scode(struct dvb_frontend *fe, unsigned int type, ...@@ -597,7 +623,7 @@ static int load_scode(struct dvb_frontend *fe, unsigned int type,
if (rc < 0) if (rc < 0)
return -EIO; return -EIO;
rc = i2c_send(priv, p + 14 * scode + 2, 12); rc = i2c_send(priv, p, 12);
if (rc < 0) if (rc < 0)
return -EIO; return -EIO;
...@@ -609,7 +635,7 @@ static int load_scode(struct dvb_frontend *fe, unsigned int type, ...@@ -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, 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 xc2028_data *priv = fe->tuner_priv;
struct firmware_properties new_fw; struct firmware_properties new_fw;
...@@ -639,6 +665,7 @@ static int check_firmware(struct dvb_frontend *fe, unsigned int type, ...@@ -639,6 +665,7 @@ static int check_firmware(struct dvb_frontend *fe, unsigned int type,
new_fw.std_req = std; new_fw.std_req = std;
new_fw.scode_table = SCODE | priv->ctrl.scode_table; new_fw.scode_table = SCODE | priv->ctrl.scode_table;
new_fw.scode_nr = 0; new_fw.scode_nr = 0;
new_fw.int_freq = int_freq;
tuner_dbg("checking firmware, user requested type="); tuner_dbg("checking firmware, user requested type=");
if (debug) { if (debug) {
...@@ -719,8 +746,8 @@ static int check_firmware(struct dvb_frontend *fe, unsigned int type, ...@@ -719,8 +746,8 @@ static int check_firmware(struct dvb_frontend *fe, unsigned int type,
/* Load SCODE firmware, if exists */ /* Load SCODE firmware, if exists */
tuner_dbg("Trying to load scode %d\n", new_fw.scode_nr); tuner_dbg("Trying to load scode %d\n", new_fw.scode_nr);
rc = load_scode(fe, new_fw.type | new_fw.scode_table, rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id,
&new_fw.id, new_fw.scode_nr); new_fw.int_freq, new_fw.scode_nr);
check_device: check_device:
if (xc2028_get_reg(priv, 0x0004, &version) < 0 || if (xc2028_get_reg(priv, 0x0004, &version) < 0 ||
...@@ -810,9 +837,10 @@ static int xc2028_signal(struct dvb_frontend *fe, u16 *strength) ...@@ -810,9 +837,10 @@ static int xc2028_signal(struct dvb_frontend *fe, u16 *strength)
#define DIV 15625 #define DIV 15625
static int generic_set_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, enum tuner_mode new_mode,
unsigned int type, unsigned int type,
v4l2_std_id std) v4l2_std_id std,
u16 int_freq)
{ {
struct xc2028_data *priv = fe->tuner_priv; struct xc2028_data *priv = fe->tuner_priv;
int rc = -EINVAL; int rc = -EINVAL;
...@@ -825,7 +853,7 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */, ...@@ -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); 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; goto ret;
/* On some cases xc2028 can disable video output, if /* On some cases xc2028 can disable video output, if
...@@ -896,7 +924,7 @@ static int xc2028_set_analog_freq(struct dvb_frontend *fe, ...@@ -896,7 +924,7 @@ static int xc2028_set_analog_freq(struct dvb_frontend *fe,
if (priv->ctrl.input1) if (priv->ctrl.input1)
type |= INPUT1; type |= INPUT1;
return generic_set_freq(fe, (625l * p->frequency) / 10, 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 */ /* if std is not defined, choose one */
...@@ -911,22 +939,9 @@ static int xc2028_set_analog_freq(struct dvb_frontend *fe, ...@@ -911,22 +939,9 @@ static int xc2028_set_analog_freq(struct dvb_frontend *fe,
p->std |= parse_audio_std_option(); p->std |= parse_audio_std_option();
return generic_set_freq(fe, 62500l * p->frequency, 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, static int xc2028_set_params(struct dvb_frontend *fe,
struct dvb_frontend_parameters *p) struct dvb_frontend_parameters *p)
{ {
...@@ -978,13 +993,12 @@ static int xc2028_set_params(struct dvb_frontend *fe, ...@@ -978,13 +993,12 @@ static int xc2028_set_params(struct dvb_frontend *fe,
tuner_err("error: bandwidth not supported.\n"); tuner_err("error: bandwidth not supported.\n");
}; };
if (priv->ctrl.demod < 0 || priv->ctrl.demod > ARRAY_SIZE(demod_type)) /* All S-code tables need a 200kHz shift */
tuner_err("error: demod type invalid. Assuming default.\n"); if (priv->ctrl.demod)
else priv->ctrl.demod += 200;
type |= demod_type[priv->ctrl.demod];
return generic_set_freq(fe, p->frequency, 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) static int xc2028_sleep(struct dvb_frontend *fe)
......
...@@ -11,19 +11,17 @@ ...@@ -11,19 +11,17 @@
#define XC2028_DEFAULT_FIRMWARE "xc3028-v27.fw" #define XC2028_DEFAULT_FIRMWARE "xc3028-v27.fw"
enum xc2028_demod_types /* Dmoduler IF (kHz) */
{ #define XC3028_FE_DEFAULT 0
XC3028_FE_DEFAULT = 0, #define XC3028_FE_LG60 6000
XC3028_FE_LG60, /* IF = 6.00 MHz */ #define XC3028_FE_ATI638 6380
XC3028_FE_ATI638, /* IF = 6.38 MHz */ #define XC3028_FE_OREN538 5380
XC3028_FE_OREN538, /* IF = 5.38 MHz */ #define XC3028_FE_OREN36 3600
XC3028_FE_OREN36, /* IF = 3.60 MHz */ #define XC3028_FE_TOYOTA388 3880
XC3028_FE_TOYOTA388, /* IF = 3.88 MHz */ #define XC3028_FE_TOYOTA794 7940
XC3028_FE_TOYOTA794, /* IF = 7.94 MHz */ #define XC3028_FE_DIBCOM52 5200
XC3028_FE_DIBCOM52, /* IF = 5.20 MHz */ #define XC3028_FE_ZARLINK456 4560
XC3028_FE_ZARLINK456, /* IF = 4.56 MHz */ #define XC3028_FE_CHINA 5200
XC3028_FE_CHINA, /* IF = 5.20 MHz */
};
struct xc2028_ctrl { struct xc2028_ctrl {
char *fname; char *fname;
...@@ -32,7 +30,7 @@ struct xc2028_ctrl { ...@@ -32,7 +30,7 @@ struct xc2028_ctrl {
unsigned int mts :1; unsigned int mts :1;
unsigned int d2633 :1; unsigned int d2633 :1;
unsigned int input1:1; unsigned int input1:1;
enum xc2028_demod_types demod; unsigned int demod;
}; };
struct xc2028_config { struct xc2028_config {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment