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.c165
1 files changed, 88 insertions, 77 deletions
diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c
index 50cf876f020..9e9003cffc7 100644
--- a/drivers/media/video/tuner-xc2028.c
+++ b/drivers/media/video/tuner-xc2028.c
@@ -1,6 +1,6 @@
/* tuner-xc2028
*
- * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org)
+ * Copyright (c) 2007-2008 Mauro Carvalho Chehab (mchehab@infradead.org)
*
* Copyright (c) 2007 Michel Ludwig (michel.ludwig@gmail.com)
* - frontend interface
@@ -23,8 +23,6 @@
#include "dvb_frontend.h"
-#define PREFIX "xc2028"
-
static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "enable verbose debug messages");
@@ -43,6 +41,11 @@ MODULE_PARM_DESC(audio_std,
"NICAM/A\n"
"NICAM/B\n");
+static char firmware_name[FIRMWARE_NAME_MAX];
+module_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0);
+MODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the "
+ "default firmware name\n");
+
static LIST_HEAD(xc2028_list);
static DEFINE_MUTEX(xc2028_list_mutex);
@@ -127,12 +130,12 @@ struct xc2028_data {
_rc; \
})
-static unsigned int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val)
+static int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val)
{
unsigned char buf[2];
unsigned char ibuf[2];
- tuner_dbg("%s %04x called\n", __FUNCTION__, reg);
+ tuner_dbg("%s %04x called\n", __func__, reg);
buf[0] = reg >> 8;
buf[1] = (unsigned char) reg;
@@ -145,7 +148,7 @@ static unsigned int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val)
}
#define dump_firm_type(t) dump_firm_type_and_int_freq(t, 0)
-void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq)
+static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq)
{
if (type & BASE)
printk("BASE ");
@@ -232,6 +235,7 @@ static v4l2_std_id parse_audio_std_option(void)
static void free_firmware(struct xc2028_data *priv)
{
int i;
+ tuner_dbg("%s called\n", __func__);
if (!priv->firm)
return;
@@ -255,19 +259,24 @@ static int load_all_firmwares(struct dvb_frontend *fe)
int rc = 0;
int n, n_array;
char name[33];
+ char *fname;
+
+ tuner_dbg("%s called\n", __func__);
- tuner_dbg("%s called\n", __FUNCTION__);
+ if (!firmware_name[0])
+ fname = priv->ctrl.fname;
+ else
+ fname = firmware_name;
- tuner_dbg("Reading firmware %s\n", priv->ctrl.fname);
- rc = request_firmware(&fw, priv->ctrl.fname,
- &priv->i2c_props.adap->dev);
+ tuner_dbg("Reading firmware %s\n", fname);
+ rc = request_firmware(&fw, fname, &priv->i2c_props.adap->dev);
if (rc < 0) {
if (rc == -ENOENT)
tuner_err("Error: firmware %s not found.\n",
- priv->ctrl.fname);
+ fname);
else
tuner_err("Error %d while requesting firmware %s \n",
- rc, priv->ctrl.fname);
+ rc, fname);
return rc;
}
@@ -276,7 +285,7 @@ static int load_all_firmwares(struct dvb_frontend *fe)
if (fw->size < sizeof(name) - 1 + 2 + 2) {
tuner_err("Error: firmware file %s has invalid size!\n",
- priv->ctrl.fname);
+ fname);
goto corrupt;
}
@@ -291,7 +300,7 @@ static int load_all_firmwares(struct dvb_frontend *fe)
p += 2;
tuner_info("Loading %d firmware images from %s, type: %s, ver %d.%d\n",
- n_array, priv->ctrl.fname, name,
+ n_array, fname, name,
priv->firm_version >> 8, priv->firm_version & 0xff);
priv->firm = kzalloc(sizeof(*priv->firm) * n_array, GFP_KERNEL);
@@ -395,9 +404,9 @@ static int seek_firmware(struct dvb_frontend *fe, unsigned int type,
{
struct xc2028_data *priv = fe->tuner_priv;
int i, best_i = -1, best_nr_matches = 0;
- unsigned int ign_firm_type_mask = 0;
+ unsigned int type_mask = 0;
- tuner_dbg("%s called, want type=", __FUNCTION__);
+ tuner_dbg("%s called, want type=", __func__);
if (debug) {
dump_firm_type(type);
printk("(%x), id %016llx.\n", type, (unsigned long long)*id);
@@ -412,18 +421,23 @@ static int seek_firmware(struct dvb_frontend *fe, unsigned int type,
*id = V4L2_STD_PAL;
if (type & BASE)
- type &= BASE_TYPES;
+ type_mask = BASE_TYPES;
else if (type & SCODE) {
type &= SCODE_TYPES;
- ign_firm_type_mask = HAS_IF;
+ type_mask = SCODE_TYPES & ~HAS_IF;
} else if (type & DTV_TYPES)
- type &= DTV_TYPES;
+ type_mask = DTV_TYPES;
else if (type & STD_SPECIFIC_TYPES)
- type &= STD_SPECIFIC_TYPES;
+ type_mask = STD_SPECIFIC_TYPES;
+
+ type &= type_mask;
+
+ if (!(type & SCODE))
+ type_mask = ~0;
/* Seek for exact match */
for (i = 0; i < priv->firm_size; i++) {
- if ((type == (priv->firm[i].type & ~ign_firm_type_mask)) &&
+ if ((type == (priv->firm[i].type & type_mask)) &&
(*id == priv->firm[i].id))
goto found;
}
@@ -433,7 +447,7 @@ static int seek_firmware(struct dvb_frontend *fe, unsigned int type,
v4l2_std_id match_mask;
int nr_matches;
- if (type != (priv->firm[i].type & ~ign_firm_type_mask))
+ if (type != (priv->firm[i].type & type_mask))
continue;
match_mask = *id & priv->firm[i].id;
@@ -483,7 +497,7 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type,
int pos, rc;
unsigned char *p, *endp, buf[priv->ctrl.max_len];
- tuner_dbg("%s called\n", __FUNCTION__);
+ tuner_dbg("%s called\n", __func__);
pos = seek_firmware(fe, type, id);
if (pos < 0)
@@ -586,7 +600,7 @@ static int load_scode(struct dvb_frontend *fe, unsigned int type,
int pos, rc;
unsigned char *p;
- tuner_dbg("%s called\n", __FUNCTION__);
+ tuner_dbg("%s called\n", __func__);
if (!int_freq) {
pos = seek_firmware(fe, type, id);
@@ -650,7 +664,7 @@ static int check_firmware(struct dvb_frontend *fe, unsigned int type,
u16 version, hwmodel;
v4l2_std_id std0;
- tuner_dbg("%s called\n", __FUNCTION__);
+ tuner_dbg("%s called\n", __func__);
if (!priv->firm) {
if (!priv->ctrl.fname) {
@@ -770,10 +784,10 @@ check_device:
goto fail;
}
- tuner_info("Device is Xceive %d version %d.%d, "
- "firmware version %d.%d\n",
- hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8,
- (version & 0xf0) >> 4, version & 0xf);
+ tuner_dbg("Device is Xceive %d version %d.%d, "
+ "firmware version %d.%d\n",
+ hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8,
+ (version & 0xf0) >> 4, version & 0xf);
/* Check firmware version against what we downloaded. */
if (priv->firm_version != ((version & 0xf0) << 4 | (version & 0x0f))) {
@@ -824,27 +838,34 @@ static int xc2028_signal(struct dvb_frontend *fe, u16 *strength)
u16 frq_lock, signal = 0;
int rc;
- tuner_dbg("%s called\n", __FUNCTION__);
+ tuner_dbg("%s called\n", __func__);
mutex_lock(&priv->lock);
/* Sync Lock Indicator */
rc = xc2028_get_reg(priv, 0x0002, &frq_lock);
- if (rc < 0 || frq_lock == 0)
+ if (rc < 0)
goto ret;
- /* Frequency is locked. Return signal quality */
+ /* Frequency is locked */
+ if (frq_lock == 1)
+ signal = 32768;
/* Get SNR of the video signal */
rc = xc2028_get_reg(priv, 0x0040, &signal);
if (rc < 0)
- signal = -frq_lock;
+ goto ret;
+
+ /* Use both frq_lock and signal to generate the result */
+ signal = signal || ((signal & 0x07) << 12);
ret:
mutex_unlock(&priv->lock);
*strength = signal;
+ tuner_dbg("signal strength is %d\n", signal);
+
return rc;
}
@@ -861,7 +882,7 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
unsigned char buf[4];
u32 div, offset = 0;
- tuner_dbg("%s called\n", __FUNCTION__);
+ tuner_dbg("%s called\n", __func__);
mutex_lock(&priv->lock);
@@ -906,9 +927,11 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
if (rc < 0)
goto ret;
- rc = priv->tuner_callback(priv->video_dev, XC2028_RESET_CLK, 1);
- if (rc < 0)
- goto ret;
+ /* Return code shouldn't be checked.
+ The reset CLK is needed only with tm6000.
+ Driver should work fine even if this fails.
+ */
+ priv->tuner_callback(priv->video_dev, XC2028_RESET_CLK, 1);
msleep(10);
@@ -942,7 +965,7 @@ static int xc2028_set_analog_freq(struct dvb_frontend *fe,
struct xc2028_data *priv = fe->tuner_priv;
unsigned int type=0;
- tuner_dbg("%s called\n", __FUNCTION__);
+ tuner_dbg("%s called\n", __func__);
if (p->mode == V4L2_TUNER_RADIO) {
type |= FM;
@@ -975,7 +998,7 @@ static int xc2028_set_params(struct dvb_frontend *fe,
fe_bandwidth_t bw = BANDWIDTH_8_MHZ;
u16 demod = 0;
- tuner_dbg("%s called\n", __FUNCTION__);
+ tuner_dbg("%s called\n", __func__);
if (priv->ctrl.d2633)
type |= D2633;
@@ -1040,33 +1063,12 @@ static int xc2028_set_params(struct dvb_frontend *fe,
T_DIGITAL_TV, type, 0, demod);
}
-static int xc2028_sleep(struct dvb_frontend *fe)
-{
- struct xc2028_data *priv = fe->tuner_priv;
- int rc = 0;
-
- tuner_dbg("%s called\n", __FUNCTION__);
-
- mutex_lock(&priv->lock);
-
- if (priv->firm_version < 0x0202)
- rc = send_seq(priv, {0x00, 0x08, 0x00, 0x00});
- else
- rc = send_seq(priv, {0x80, 0x08, 0x00, 0x00});
-
- priv->cur_fw.type = 0; /* need firmware reload */
-
- mutex_unlock(&priv->lock);
-
- return rc;
-}
-
static int xc2028_dvb_release(struct dvb_frontend *fe)
{
struct xc2028_data *priv = fe->tuner_priv;
- tuner_dbg("%s called\n", __FUNCTION__);
+ tuner_dbg("%s called\n", __func__);
mutex_lock(&xc2028_list_mutex);
@@ -1091,7 +1093,7 @@ static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency)
{
struct xc2028_data *priv = fe->tuner_priv;
- tuner_dbg("%s called\n", __FUNCTION__);
+ tuner_dbg("%s called\n", __func__);
*frequency = priv->frequency;
@@ -1104,25 +1106,25 @@ static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg)
struct xc2028_ctrl *p = priv_cfg;
int rc = 0;
- tuner_dbg("%s called\n", __FUNCTION__);
+ tuner_dbg("%s called\n", __func__);
mutex_lock(&priv->lock);
- kfree(priv->ctrl.fname);
- free_firmware(priv);
-
memcpy(&priv->ctrl, p, sizeof(priv->ctrl));
- priv->ctrl.fname = NULL;
+ if (priv->ctrl.max_len < 9)
+ priv->ctrl.max_len = 13;
if (p->fname) {
+ if (priv->ctrl.fname && strcmp(p->fname, priv->ctrl.fname)) {
+ kfree(priv->ctrl.fname);
+ free_firmware(priv);
+ }
+
priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL);
if (priv->ctrl.fname == NULL)
rc = -ENOMEM;
}
- if (priv->ctrl.max_len < 9)
- priv->ctrl.max_len = 13;
-
mutex_unlock(&priv->lock);
return rc;
@@ -1142,8 +1144,6 @@ static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = {
.get_frequency = xc2028_get_frequency,
.get_rf_strength = xc2028_signal,
.set_params = xc2028_set_params,
- .sleep = xc2028_sleep,
-
};
struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
@@ -1153,23 +1153,29 @@ struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
void *video_dev;
if (debug)
- printk(KERN_DEBUG PREFIX ": Xcv2028/3028 init called!\n");
+ printk(KERN_DEBUG "xc2028: Xcv2028/3028 init called!\n");
- if (NULL == cfg || NULL == cfg->video_dev)
+ if (NULL == cfg)
return NULL;
if (!fe) {
- printk(KERN_ERR PREFIX ": No frontend!\n");
+ printk(KERN_ERR "xc2028: No frontend!\n");
return NULL;
}
- video_dev = cfg->video_dev;
+ video_dev = cfg->i2c_adap->algo_data;
+
+ if (debug)
+ printk(KERN_DEBUG "xc2028: video_dev =%p\n", video_dev);
mutex_lock(&xc2028_list_mutex);
list_for_each_entry(priv, &xc2028_list, xc2028_list) {
- if (priv->video_dev == cfg->video_dev) {
+ if (&priv->i2c_props.adap->dev == &cfg->i2c_adap->dev) {
video_dev = NULL;
+ if (debug)
+ printk(KERN_DEBUG "xc2028: reusing device\n");
+
break;
}
}
@@ -1183,6 +1189,8 @@ struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
priv->i2c_props.addr = cfg->i2c_addr;
priv->i2c_props.adap = cfg->i2c_adap;
+ priv->i2c_props.name = "xc2028";
+
priv->video_dev = video_dev;
priv->tuner_callback = cfg->callback;
priv->ctrl.max_len = 13;
@@ -1195,6 +1203,9 @@ struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
fe->tuner_priv = priv;
priv->count++;
+ if (debug)
+ printk(KERN_DEBUG "xc2028: usage count is %i\n", priv->count);
+
memcpy(&fe->ops.tuner_ops, &xc2028_dvb_tuner_ops,
sizeof(xc2028_dvb_tuner_ops));