Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 76455
b: refs/heads/master
c: e0f0b37
h: refs/heads/master
i:
  76453: d3a16fc
  76451: 2a52d65
  76447: 2604eb5
v: v3
  • Loading branch information
Chris Pascoe authored and Mauro Carvalho Chehab committed Jan 25, 2008
1 parent 664d971 commit 219d5e3
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 98 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 59a636e50f339f91880b3a1e395829c43cc6541a
refs/heads/master: e0f0b37a3e624440b1b0e8a5978b367895226e75
8 changes: 8 additions & 0 deletions trunk/drivers/media/video/tuner-xc2028-types.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

/* BASE firmware should be loaded before any other firmware */
#define BASE (1<<0)
#define BASE_TYPES (BASE|F8MHZ|MTS|FM|INPUT1|INPUT2|INIT1)

/* F8MHZ marks BASE firmwares for 8 MHz Bandwidth */
#define F8MHZ (1<<1)
Expand Down Expand Up @@ -37,6 +38,8 @@
#define DTV78 (1<<8)
#define DTV8 (1<<9)

#define DTV_TYPES (D2620|D2633|DTV6|QAM|DTV7|DTV78|DTV8|ATSC)

/* There's a FM | BASE firmware + FM specific firmware (std=0) */
#define FM (1<<10)

Expand All @@ -60,6 +63,7 @@
/* Old firmwares were broken into init0 and init1 */
#define INIT1 (1<<14)

/* SCODE firmware selects particular behaviours */
#define MONO (1 << 15)
#define ATSC (1 << 16)
#define IF (1 << 17)
Expand All @@ -76,6 +80,10 @@
#define INPUT2 (1 << 28)
#define SCODE (1 << 29)

#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)

/* Newer types to be moved to videodev2.h */

#define V4L2_STD_SECAM_K3 (0x04000000)
Expand Down
212 changes: 115 additions & 97 deletions trunk/drivers/media/video/tuner-xc2028.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,14 @@ struct firmware_description {
unsigned int size;
};

struct firmware_properties {
unsigned int type;
v4l2_std_id id;
v4l2_std_id std_req;
unsigned int scode_table;
int scode_nr;
};

struct xc2028_data {
struct list_head xc2028_list;
struct tuner_i2c_props i2c_props;
Expand All @@ -69,14 +77,7 @@ struct xc2028_data {

struct xc2028_ctrl ctrl;

v4l2_std_id firm_type; /* video stds supported
by current firmware */
fe_bandwidth_t bandwidth; /* Firmware bandwidth:
6M, 7M or 8M */
int need_load_generic; /* The generic firmware
were loaded? */
enum tuner_mode mode;
struct i2c_client *i2c_client;
struct firmware_properties cur_fw;

struct mutex lock;
};
Expand Down Expand Up @@ -234,7 +235,8 @@ static void free_firmware(struct xc2028_data *priv)

priv->firm = NULL;
priv->firm_size = 0;
priv->need_load_generic = 1;

memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
}

static int load_all_firmwares(struct dvb_frontend *fe)
Expand Down Expand Up @@ -393,6 +395,13 @@ static int seek_firmware(struct dvb_frontend *fe, unsigned int type,
if (((type & ~SCODE) == 0) && (*id == 0))
*id = V4L2_STD_PAL;

if (type & BASE)
type &= BASE_TYPES;
else if (type & SCODE)
type &= SCODE_TYPES;
else if (type & DTV_TYPES)
type = type & DTV_TYPES;

/* Seek for exact match */
for (i = 0; i < priv->firm_size; i++) {
if ((type == priv->firm[i].type) && (*id == priv->firm[i].id))
Expand Down Expand Up @@ -598,11 +607,10 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode,
v4l2_std_id std, fe_bandwidth_t bandwidth)
{
struct xc2028_data *priv = fe->tuner_priv;
int rc;
int rc = 0;
unsigned int type = 0;
struct firmware_properties new_fw;
u16 version, hwmodel;
v4l2_std_id std0 = 0;
unsigned int type0 = 0, type = 0;
int change_digital_bandwidth;

tuner_dbg("%s called\n", __FUNCTION__);

Expand All @@ -617,61 +625,19 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode,
return rc;
}

tuner_dbg("I am in mode %u and I should switch to mode %i\n",
priv->mode, new_mode);

/* first of all, determine whether we have switched the mode */
if (new_mode != priv->mode) {
priv->mode = new_mode;
priv->need_load_generic = 1;
}

change_digital_bandwidth = (priv->mode == T_DIGITAL_TV
&& bandwidth != priv->bandwidth) ? 1 : 0;
tuner_dbg("old bandwidth %u, new bandwidth %u\n", priv->bandwidth,
bandwidth);

if (priv->need_load_generic) {
/* Reset is needed before loading firmware */
rc = priv->tuner_callback(priv->video_dev,
XC2028_TUNER_RESET, 0);
if (rc < 0)
return rc;

type0 = BASE;

if (priv->ctrl.type == XC2028_FIRM_MTS)
type0 |= MTS;

if (bandwidth == BANDWIDTH_7_MHZ ||
bandwidth == BANDWIDTH_8_MHZ)
type0 |= F8MHZ;

/* FIXME: How to load FM and FM|INPUT1 firmwares? */

rc = load_firmware(fe, type0, &std0);
if (rc < 0) {
tuner_err("Error %d while loading generic firmware\n",
rc);
return rc;
}

priv->need_load_generic = 0;
priv->firm_type = 0;
if (priv->mode == T_DIGITAL_TV)
change_digital_bandwidth = 1;
}
if (priv->ctrl.type == XC2028_FIRM_MTS)
type |= MTS;
if (bandwidth == BANDWIDTH_7_MHZ || bandwidth == BANDWIDTH_8_MHZ)
type |= F8MHZ;

tuner_dbg("I should change bandwidth %u\n", change_digital_bandwidth);
/* FIXME: How to load FM and FM|INPUT1 firmwares? */

if (change_digital_bandwidth) {
if (new_mode == T_DIGITAL_TV) {
if (priv->ctrl.d2633)
type |= D2633;
else
type |= D2620;

/* FIXME: When should select a DTV78 firmware?
*/
switch (bandwidth) {
case BANDWIDTH_8_MHZ:
type |= DTV8;
Expand All @@ -683,49 +649,96 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode,
/* FIXME: Should allow select also ATSC */
type |= DTV6 | QAM;
break;

default:
tuner_err("error: bandwidth not supported.\n");
};
priv->bandwidth = bandwidth;
}

if (!change_digital_bandwidth && priv->mode == T_DIGITAL_TV)
return 0;
new_fw.type = type;
new_fw.id = std;
new_fw.std_req = std;
new_fw.scode_table = SCODE | priv->ctrl.scode_table;
new_fw.scode_nr = 0;

tuner_dbg("checking firmware, user requested type=");
if (debug) {
dump_firm_type(new_fw.type);
printk("(%x), id %016llx, scode_tbl ", new_fw.type,
(unsigned long long)new_fw.std_req);
dump_firm_type(priv->ctrl.scode_table);
printk("(%x), scode_nr %d\n", priv->ctrl.scode_table,
new_fw.scode_nr);
}

/* No need to reload base firmware if it matches */
if (((BASE | new_fw.type) & BASE_TYPES) ==
(priv->cur_fw.type & BASE_TYPES)) {
tuner_dbg("BASE firmware not changed.\n");
goto skip_base;
}

/* Updating BASE - forget about all currently loaded firmware */
memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));

/* Reset is needed before loading firmware */
rc = priv->tuner_callback(priv->video_dev,
XC2028_TUNER_RESET, 0);
if (rc < 0)
goto fail;

rc = load_firmware(fe, BASE | new_fw.type, &new_fw.id);
if (rc < 0) {
tuner_err("Error %d while loading base firmware\n",
rc);
goto fail;
}

/* Load INIT1, if needed */
tuner_dbg("Load init1 firmware, if exists\n");
type0 = BASE | INIT1;
if (priv->ctrl.type == XC2028_FIRM_MTS)
type0 |= MTS;

/* FIXME: Should handle errors - if INIT1 found */
rc = load_firmware(fe, type0, &std0);
rc = load_firmware(fe, BASE | INIT1 | new_fw.type, &new_fw.id);
if (rc < 0 && rc != -ENOENT) {
tuner_err("Error %d while loading init1 firmware\n",
rc);
goto fail;
}

/* FIXME: Should add support for FM radio
skip_base:
/*
* No need to reload standard specific firmware if base firmware
* was not reloaded and requested video standards have not changed.
*/

if (priv->ctrl.type == XC2028_FIRM_MTS)
type |= MTS;

if (priv->firm_type & std) {
if (priv->cur_fw.type == (BASE | new_fw.type) &&
priv->cur_fw.std_req == std) {
tuner_dbg("Std-specific firmware already loaded.\n");
return 0;
goto skip_std_specific;
}

/* Reloading std-specific firmware forces a SCODE update */
priv->cur_fw.scode_table = 0;

/* Add audio hack to std mask */
std |= parse_audio_std_option();
if (new_mode == T_ANALOG_TV)
new_fw.id |= parse_audio_std_option();

rc = load_firmware(fe, type, &std);
rc = load_firmware(fe, new_fw.type, &new_fw.id);
if (rc < 0)
return rc;
goto fail;

skip_std_specific:
if (priv->cur_fw.scode_table == new_fw.scode_table &&
priv->cur_fw.scode_nr == new_fw.scode_nr) {
tuner_dbg("SCODE firmware already loaded.\n");
goto check_device;
}

/* Load SCODE firmware, if exists */
tuner_dbg("Trying to load scode 0\n");
type |= SCODE;
tuner_dbg("Trying to load scode %d\n", new_fw.scode_nr);

rc = load_scode(fe, type, &std, 0);
rc = load_scode(fe, new_fw.type | new_fw.scode_table,
&new_fw.id, new_fw.scode_nr);

check_device:
xc2028_get_reg(priv, 0x0004, &version);
xc2028_get_reg(priv, 0x0008, &hwmodel);

Expand All @@ -734,9 +747,23 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode,
hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8,
(version & 0xf0) >> 4, version & 0xf);

priv->firm_type = std;
memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw));

/*
* By setting BASE in cur_fw.type only after successfully loading all
* firmwares, we can:
* 1. Identify that BASE firmware with type=0 has been loaded;
* 2. Tell whether BASE firmware was just changed the next time through.
*/
priv->cur_fw.type |= BASE;

return 0;

fail:
memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
if (rc == -ENOENT)
rc = -EINVAL;
return rc;
}

static int xc2028_signal(struct dvb_frontend *fe, u16 *strength)
Expand Down Expand Up @@ -785,24 +812,18 @@ static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */ ,
mutex_lock(&priv->lock);

/* HACK: It seems that specific firmware need to be reloaded
when freq is changed */

priv->firm_type = 0;

/* Reset GPIO 1 */
rc = priv->tuner_callback(priv->video_dev, XC2028_TUNER_RESET, 0);
if (rc < 0)
goto ret;
when watching analog TV and freq is changed */
if (new_mode != T_DIGITAL_TV)
priv->cur_fw.type = 0;

msleep(10);
tuner_dbg("should set frequency %d kHz\n", freq / 1000);

if (check_firmware(fe, new_mode, std, bandwidth) < 0)
goto ret;

if (new_mode == T_DIGITAL_TV) {
offset = 2750000;
if (priv->bandwidth == BANDWIDTH_7_MHZ)
if (priv->cur_fw.type & DTV7)
offset -= 500000;
}

Expand Down Expand Up @@ -994,9 +1015,6 @@ void *xc2028_attach(struct dvb_frontend *fe, struct xc2028_config *cfg)
return NULL;
}

priv->bandwidth = BANDWIDTH_6_MHZ;
priv->need_load_generic = 1;
priv->mode = T_UNINITIALIZED;
priv->i2c_props.addr = cfg->i2c_addr;
priv->i2c_props.adap = cfg->i2c_adap;
priv->video_dev = video_dev;
Expand Down
1 change: 1 addition & 0 deletions trunk/drivers/media/video/tuner-xc2028.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ struct xc2028_ctrl {
char *fname;
int max_len;
int d2633:1;
unsigned int scode_table;
};

struct xc2028_config {
Expand Down

0 comments on commit 219d5e3

Please sign in to comment.