summaryrefslogtreecommitdiff
path: root/drivers/media/common/tuners/xc5000.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/common/tuners/xc5000.c')
-rw-r--r--drivers/media/common/tuners/xc5000.c109
1 files changed, 77 insertions, 32 deletions
diff --git a/drivers/media/common/tuners/xc5000.c b/drivers/media/common/tuners/xc5000.c
index dcddfa803a7..f9c2bb917f5 100644
--- a/drivers/media/common/tuners/xc5000.c
+++ b/drivers/media/common/tuners/xc5000.c
@@ -30,7 +30,7 @@
#include "dvb_frontend.h"
#include "xc5000.h"
-#include "xc5000_priv.h"
+#include "tuner-i2c.h"
static int debug;
module_param(debug, int, 0644);
@@ -40,12 +40,26 @@ static int xc5000_load_fw_on_attach;
module_param_named(init_fw, xc5000_load_fw_on_attach, int, 0644);
MODULE_PARM_DESC(init_fw, "Load firmware during driver initialization.");
+static DEFINE_MUTEX(xc5000_list_mutex);
+static LIST_HEAD(hybrid_tuner_instance_list);
+
#define dprintk(level,fmt, arg...) if (debug >= level) \
printk(KERN_INFO "%s: " fmt, "xc5000", ## arg)
#define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.1.fw"
#define XC5000_DEFAULT_FIRMWARE_SIZE 12332
+struct xc5000_priv {
+ struct tuner_i2c_props i2c_props;
+ struct list_head hybrid_tuner_instance_list;
+
+ u32 if_khz;
+ u32 freq_hz;
+ u32 bandwidth;
+ u8 video_standard;
+ u8 rf_mode;
+};
+
/* Misc Defines */
#define MAX_TV_STANDARD 23
#define XC_MAX_I2C_WRITE_LENGTH 64
@@ -216,9 +230,12 @@ static void xc5000_TunerReset(struct dvb_frontend *fe)
dprintk(1, "%s()\n", __func__);
- if (priv->cfg->tuner_callback) {
- ret = priv->cfg->tuner_callback(priv->devptr,
- XC5000_TUNER_RESET, 0);
+ if (fe->callback) {
+ ret = fe->callback(((fe->dvb) && (fe->dvb->priv)) ?
+ fe->dvb->priv :
+ priv->i2c_props.adap->algo_data,
+ DVB_FRONTEND_COMPONENT_TUNER,
+ XC5000_TUNER_RESET, 0);
if (ret)
printk(KERN_ERR "xc5000: reset failed\n");
} else
@@ -509,13 +526,13 @@ static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
u8 buf[2] = { reg >> 8, reg & 0xff };
u8 bval[2] = { 0, 0 };
struct i2c_msg msg[2] = {
- { .addr = priv->cfg->i2c_address,
+ { .addr = priv->i2c_props.addr,
.flags = 0, .buf = &buf[0], .len = 2 },
- { .addr = priv->cfg->i2c_address,
+ { .addr = priv->i2c_props.addr,
.flags = I2C_M_RD, .buf = &bval[0], .len = 2 },
};
- if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+ if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) {
printk(KERN_WARNING "xc5000: I2C read failed\n");
return -EREMOTEIO;
}
@@ -526,10 +543,10 @@ static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len)
{
- struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
+ struct i2c_msg msg = { .addr = priv->i2c_props.addr,
.flags = 0, .buf = buf, .len = len };
- if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+ if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n",
(int)len);
return -EREMOTEIO;
@@ -539,10 +556,10 @@ static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len)
static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len)
{
- struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
+ struct i2c_msg msg = { .addr = priv->i2c_props.addr,
.flags = I2C_M_RD, .buf = buf, .len = len };
- if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+ if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n",(int)len);
return -EREMOTEIO;
}
@@ -559,7 +576,7 @@ static int xc5000_fwupload(struct dvb_frontend* fe)
printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n",
XC5000_DEFAULT_FIRMWARE);
- ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, &priv->i2c->dev);
+ ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, &priv->i2c_props.adap->dev);
if (ret) {
printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n");
ret = XC_RESULT_RESET_FAILURE;
@@ -675,10 +692,10 @@ static int xc5000_set_params(struct dvb_frontend *fe,
return -EREMOTEIO;
}
- ret = xc_set_IF_frequency(priv, priv->cfg->if_khz);
+ ret = xc_set_IF_frequency(priv, priv->if_khz);
if (ret != XC_RESULT_SUCCESS) {
printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n",
- priv->cfg->if_khz);
+ priv->if_khz);
return -EIO;
}
@@ -897,9 +914,19 @@ static int xc5000_init(struct dvb_frontend *fe)
static int xc5000_release(struct dvb_frontend *fe)
{
+ struct xc5000_priv *priv = fe->tuner_priv;
+
dprintk(1, "%s()\n", __func__);
- kfree(fe->tuner_priv);
+
+ mutex_lock(&xc5000_list_mutex);
+
+ if (priv)
+ hybrid_tuner_release_state(priv);
+
+ mutex_unlock(&xc5000_list_mutex);
+
fe->tuner_priv = NULL;
+
return 0;
}
@@ -924,29 +951,43 @@ static const struct dvb_tuner_ops xc5000_tuner_ops = {
struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
- struct xc5000_config *cfg, void *devptr)
+ struct xc5000_config *cfg)
{
struct xc5000_priv *priv = NULL;
+ int instance;
u16 id = 0;
- dprintk(1, "%s()\n", __func__);
+ dprintk(1, "%s(%d-%04x)\n", __func__,
+ i2c ? i2c_adapter_id(i2c) : -1,
+ cfg ? cfg->i2c_address : -1);
- priv = kzalloc(sizeof(struct xc5000_priv), GFP_KERNEL);
- if (priv == NULL)
- return NULL;
+ mutex_lock(&xc5000_list_mutex);
- priv->cfg = cfg;
- priv->bandwidth = BANDWIDTH_6_MHZ;
- priv->i2c = i2c;
- priv->devptr = devptr;
+ instance = hybrid_tuner_request_state(struct xc5000_priv, priv,
+ hybrid_tuner_instance_list,
+ i2c, cfg->i2c_address, "xc5000");
+ switch (instance) {
+ case 0:
+ goto fail;
+ break;
+ case 1:
+ /* new tuner instance */
+ priv->bandwidth = BANDWIDTH_6_MHZ;
+ priv->if_khz = cfg->if_khz;
+
+ fe->tuner_priv = priv;
+ break;
+ default:
+ /* existing tuner instance */
+ fe->tuner_priv = priv;
+ break;
+ }
/* Check if firmware has been loaded. It is possible that another
instance of the driver has loaded the firmware.
*/
- if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0) {
- kfree(priv);
- return NULL;
- }
+ if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0)
+ goto fail;
switch(id) {
case XC_PRODUCT_ID_FW_LOADED:
@@ -967,19 +1008,23 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
printk(KERN_ERR
"xc5000: Device not found at addr 0x%02x (0x%x)\n",
cfg->i2c_address, id);
- kfree(priv);
- return NULL;
+ goto fail;
}
+ mutex_unlock(&xc5000_list_mutex);
+
memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops,
sizeof(struct dvb_tuner_ops));
- fe->tuner_priv = priv;
-
if (xc5000_load_fw_on_attach)
xc5000_init(fe);
return fe;
+fail:
+ mutex_unlock(&xc5000_list_mutex);
+
+ xc5000_release(fe);
+ return NULL;
}
EXPORT_SYMBOL(xc5000_attach);