[media] ttusb2: add support for the dvb-t part of CT-3650 v3
Signed-off-by: Jose Alberto Reguero <jareguero@telefonica.net> Reviewed-by: Antti Palosaari <crope@iki.fi> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
committed by
Mauro Carvalho Chehab
parent
84b271488d
commit
c9f88aa976
@@ -30,6 +30,7 @@
|
|||||||
#include "tda826x.h"
|
#include "tda826x.h"
|
||||||
#include "tda10086.h"
|
#include "tda10086.h"
|
||||||
#include "tda1002x.h"
|
#include "tda1002x.h"
|
||||||
|
#include "tda10048.h"
|
||||||
#include "tda827x.h"
|
#include "tda827x.h"
|
||||||
#include "lnbp21.h"
|
#include "lnbp21.h"
|
||||||
|
|
||||||
@@ -82,7 +83,7 @@ static int ttusb2_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num
|
|||||||
{
|
{
|
||||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||||
static u8 obuf[60], ibuf[60];
|
static u8 obuf[60], ibuf[60];
|
||||||
int i,read;
|
int i, write_read, read;
|
||||||
|
|
||||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
@@ -91,14 +92,20 @@ static int ttusb2_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num
|
|||||||
warn("more than 2 i2c messages at a time is not handled yet. TODO.");
|
warn("more than 2 i2c messages at a time is not handled yet. TODO.");
|
||||||
|
|
||||||
for (i = 0; i < num; i++) {
|
for (i = 0; i < num; i++) {
|
||||||
read = i+1 < num && (msg[i+1].flags & I2C_M_RD);
|
write_read = i+1 < num && (msg[i+1].flags & I2C_M_RD);
|
||||||
|
read = msg[i].flags & I2C_M_RD;
|
||||||
|
|
||||||
obuf[0] = (msg[i].addr << 1) | read;
|
obuf[0] = (msg[i].addr << 1) | (write_read | read);
|
||||||
|
if (read)
|
||||||
|
obuf[1] = 0;
|
||||||
|
else
|
||||||
obuf[1] = msg[i].len;
|
obuf[1] = msg[i].len;
|
||||||
|
|
||||||
/* read request */
|
/* read request */
|
||||||
if (read)
|
if (write_read)
|
||||||
obuf[2] = msg[i+1].len;
|
obuf[2] = msg[i+1].len;
|
||||||
|
else if (read)
|
||||||
|
obuf[2] = msg[i].len;
|
||||||
else
|
else
|
||||||
obuf[2] = 0;
|
obuf[2] = 0;
|
||||||
|
|
||||||
@@ -109,10 +116,11 @@ static int ttusb2_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (read) {
|
if (write_read) {
|
||||||
memcpy(msg[i+1].buf, &ibuf[3], msg[i+1].len);
|
memcpy(msg[i+1].buf, &ibuf[3], msg[i+1].len);
|
||||||
i++;
|
i++;
|
||||||
}
|
} else if (read)
|
||||||
|
memcpy(msg[i].buf, &ibuf[3], msg[i].len);
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_unlock(&d->i2c_mutex);
|
mutex_unlock(&d->i2c_mutex);
|
||||||
@@ -190,6 +198,25 @@ static struct tda10023_config tda10023_config = {
|
|||||||
.deltaf = 0xa511,
|
.deltaf = 0xa511,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct tda10048_config tda10048_config = {
|
||||||
|
.demod_address = 0x10 >> 1,
|
||||||
|
.output_mode = TDA10048_PARALLEL_OUTPUT,
|
||||||
|
.inversion = TDA10048_INVERSION_ON,
|
||||||
|
.dtv6_if_freq_khz = TDA10048_IF_4000,
|
||||||
|
.dtv7_if_freq_khz = TDA10048_IF_4500,
|
||||||
|
.dtv8_if_freq_khz = TDA10048_IF_5000,
|
||||||
|
.clk_freq_khz = TDA10048_CLK_16000,
|
||||||
|
.no_firmware = 1,
|
||||||
|
.set_pll = true ,
|
||||||
|
.pll_m = 5,
|
||||||
|
.pll_n = 3,
|
||||||
|
.pll_p = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct tda827x_config tda827x_config = {
|
||||||
|
.config = 0,
|
||||||
|
};
|
||||||
|
|
||||||
static int ttusb2_frontend_tda10086_attach(struct dvb_usb_adapter *adap)
|
static int ttusb2_frontend_tda10086_attach(struct dvb_usb_adapter *adap)
|
||||||
{
|
{
|
||||||
if (usb_set_interface(adap->dev->udev,0,3) < 0)
|
if (usb_set_interface(adap->dev->udev,0,3) < 0)
|
||||||
@@ -203,20 +230,56 @@ static int ttusb2_frontend_tda10086_attach(struct dvb_usb_adapter *adap)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ttusb2_ct3650_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
|
||||||
|
{
|
||||||
|
struct dvb_usb_adapter *adap = fe->dvb->priv;
|
||||||
|
|
||||||
|
return adap->fe[0]->ops.i2c_gate_ctrl(adap->fe[0], enable);
|
||||||
|
}
|
||||||
|
|
||||||
static int ttusb2_frontend_tda10023_attach(struct dvb_usb_adapter *adap)
|
static int ttusb2_frontend_tda10023_attach(struct dvb_usb_adapter *adap)
|
||||||
{
|
{
|
||||||
if (usb_set_interface(adap->dev->udev, 0, 3) < 0)
|
if (usb_set_interface(adap->dev->udev, 0, 3) < 0)
|
||||||
err("set interface to alts=3 failed");
|
err("set interface to alts=3 failed");
|
||||||
if ((adap->fe[0] = dvb_attach(tda10023_attach, &tda10023_config, &adap->dev->i2c_adap, 0x48)) == NULL) {
|
|
||||||
|
if (adap->fe[0] == NULL) {
|
||||||
|
/* FE 0 DVB-C */
|
||||||
|
adap->fe[0] = dvb_attach(tda10023_attach,
|
||||||
|
&tda10023_config, &adap->dev->i2c_adap, 0x48);
|
||||||
|
|
||||||
|
if (adap->fe[0] == NULL) {
|
||||||
deb_info("TDA10023 attach failed\n");
|
deb_info("TDA10023 attach failed\n");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
adap->fe[1] = dvb_attach(tda10048_attach,
|
||||||
|
&tda10048_config, &adap->dev->i2c_adap);
|
||||||
|
|
||||||
|
if (adap->fe[1] == NULL) {
|
||||||
|
deb_info("TDA10048 attach failed\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tuner is behind TDA10023 I2C-gate */
|
||||||
|
adap->fe[1]->ops.i2c_gate_ctrl = ttusb2_ct3650_i2c_gate_ctrl;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ttusb2_tuner_tda827x_attach(struct dvb_usb_adapter *adap)
|
static int ttusb2_tuner_tda827x_attach(struct dvb_usb_adapter *adap)
|
||||||
{
|
{
|
||||||
if (dvb_attach(tda827x_attach, adap->fe[0], 0x61, &adap->dev->i2c_adap, NULL) == NULL) {
|
struct dvb_frontend *fe;
|
||||||
|
|
||||||
|
/* MFE: select correct FE to attach tuner since that's called twice */
|
||||||
|
if (adap->fe[1] == NULL)
|
||||||
|
fe = adap->fe[0];
|
||||||
|
else
|
||||||
|
fe = adap->fe[1];
|
||||||
|
|
||||||
|
/* attach tuner */
|
||||||
|
if (dvb_attach(tda827x_attach, fe, 0x61, &adap->dev->i2c_adap, &tda827x_config) == NULL) {
|
||||||
printk(KERN_ERR "%s: No tda827x found!\n", __func__);
|
printk(KERN_ERR "%s: No tda827x found!\n", __func__);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
@@ -385,6 +448,7 @@ static struct dvb_usb_device_properties ttusb2_properties_ct3650 = {
|
|||||||
{
|
{
|
||||||
.streaming_ctrl = NULL,
|
.streaming_ctrl = NULL,
|
||||||
|
|
||||||
|
.num_frontends = 2,
|
||||||
.frontend_attach = ttusb2_frontend_tda10023_attach,
|
.frontend_attach = ttusb2_frontend_tda10023_attach,
|
||||||
.tuner_attach = ttusb2_tuner_tda827x_attach,
|
.tuner_attach = ttusb2_tuner_tda827x_attach,
|
||||||
|
|
||||||
|
@@ -206,15 +206,16 @@ static struct init_tab {
|
|||||||
static struct pll_tab {
|
static struct pll_tab {
|
||||||
u32 clk_freq_khz;
|
u32 clk_freq_khz;
|
||||||
u32 if_freq_khz;
|
u32 if_freq_khz;
|
||||||
u8 m, n, p;
|
|
||||||
} pll_tab[] = {
|
} pll_tab[] = {
|
||||||
{ TDA10048_CLK_4000, TDA10048_IF_36130, 10, 0, 0 },
|
{ TDA10048_CLK_4000, TDA10048_IF_36130 },
|
||||||
{ TDA10048_CLK_16000, TDA10048_IF_3300, 10, 3, 0 },
|
{ TDA10048_CLK_16000, TDA10048_IF_3300 },
|
||||||
{ TDA10048_CLK_16000, TDA10048_IF_3500, 10, 3, 0 },
|
{ TDA10048_CLK_16000, TDA10048_IF_3500 },
|
||||||
{ TDA10048_CLK_16000, TDA10048_IF_3800, 10, 3, 0 },
|
{ TDA10048_CLK_16000, TDA10048_IF_3800 },
|
||||||
{ TDA10048_CLK_16000, TDA10048_IF_4000, 10, 3, 0 },
|
{ TDA10048_CLK_16000, TDA10048_IF_4000 },
|
||||||
{ TDA10048_CLK_16000, TDA10048_IF_4300, 10, 3, 0 },
|
{ TDA10048_CLK_16000, TDA10048_IF_4300 },
|
||||||
{ TDA10048_CLK_16000, TDA10048_IF_36130, 10, 3, 0 },
|
{ TDA10048_CLK_16000, TDA10048_IF_4500 },
|
||||||
|
{ TDA10048_CLK_16000, TDA10048_IF_5000 },
|
||||||
|
{ TDA10048_CLK_16000, TDA10048_IF_36130 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static int tda10048_writereg(struct tda10048_state *state, u8 reg, u8 data)
|
static int tda10048_writereg(struct tda10048_state *state, u8 reg, u8 data)
|
||||||
@@ -460,9 +461,6 @@ static int tda10048_set_if(struct dvb_frontend *fe, enum fe_bandwidth bw)
|
|||||||
|
|
||||||
state->freq_if_hz = pll_tab[i].if_freq_khz * 1000;
|
state->freq_if_hz = pll_tab[i].if_freq_khz * 1000;
|
||||||
state->xtal_hz = pll_tab[i].clk_freq_khz * 1000;
|
state->xtal_hz = pll_tab[i].clk_freq_khz * 1000;
|
||||||
state->pll_mfactor = pll_tab[i].m;
|
|
||||||
state->pll_nfactor = pll_tab[i].n;
|
|
||||||
state->pll_pfactor = pll_tab[i].p;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -781,6 +779,10 @@ static int tda10048_init(struct dvb_frontend *fe)
|
|||||||
|
|
||||||
dprintk(1, "%s()\n", __func__);
|
dprintk(1, "%s()\n", __func__);
|
||||||
|
|
||||||
|
/* PLL */
|
||||||
|
init_tab[4].data = (u8)(state->pll_mfactor);
|
||||||
|
init_tab[5].data = (u8)(state->pll_nfactor) | 0x40;
|
||||||
|
|
||||||
/* Apply register defaults */
|
/* Apply register defaults */
|
||||||
for (i = 0; i < ARRAY_SIZE(init_tab); i++)
|
for (i = 0; i < ARRAY_SIZE(init_tab); i++)
|
||||||
tda10048_writereg(state, init_tab[i].reg, init_tab[i].data);
|
tda10048_writereg(state, init_tab[i].reg, init_tab[i].data);
|
||||||
@@ -1123,7 +1125,7 @@ struct dvb_frontend *tda10048_attach(const struct tda10048_config *config,
|
|||||||
/* setup the state and clone the config */
|
/* setup the state and clone the config */
|
||||||
memcpy(&state->config, config, sizeof(*config));
|
memcpy(&state->config, config, sizeof(*config));
|
||||||
state->i2c = i2c;
|
state->i2c = i2c;
|
||||||
state->fwloaded = 0;
|
state->fwloaded = config->no_firmware;
|
||||||
state->bandwidth = BANDWIDTH_8_MHZ;
|
state->bandwidth = BANDWIDTH_8_MHZ;
|
||||||
|
|
||||||
/* check if the demod is present */
|
/* check if the demod is present */
|
||||||
@@ -1135,6 +1137,17 @@ struct dvb_frontend *tda10048_attach(const struct tda10048_config *config,
|
|||||||
sizeof(struct dvb_frontend_ops));
|
sizeof(struct dvb_frontend_ops));
|
||||||
state->frontend.demodulator_priv = state;
|
state->frontend.demodulator_priv = state;
|
||||||
|
|
||||||
|
/* set pll */
|
||||||
|
if (config->set_pll) {
|
||||||
|
state->pll_mfactor = config->pll_m;
|
||||||
|
state->pll_nfactor = config->pll_n;
|
||||||
|
state->pll_pfactor = config->pll_p;
|
||||||
|
} else {
|
||||||
|
state->pll_mfactor = 10;
|
||||||
|
state->pll_nfactor = 3;
|
||||||
|
state->pll_pfactor = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Establish any defaults the the user didn't pass */
|
/* Establish any defaults the the user didn't pass */
|
||||||
tda10048_establish_defaults(&state->frontend);
|
tda10048_establish_defaults(&state->frontend);
|
||||||
|
|
||||||
|
@@ -51,6 +51,7 @@ struct tda10048_config {
|
|||||||
#define TDA10048_IF_4300 4300
|
#define TDA10048_IF_4300 4300
|
||||||
#define TDA10048_IF_4500 4500
|
#define TDA10048_IF_4500 4500
|
||||||
#define TDA10048_IF_4750 4750
|
#define TDA10048_IF_4750 4750
|
||||||
|
#define TDA10048_IF_5000 5000
|
||||||
#define TDA10048_IF_36130 36130
|
#define TDA10048_IF_36130 36130
|
||||||
u16 dtv6_if_freq_khz;
|
u16 dtv6_if_freq_khz;
|
||||||
u16 dtv7_if_freq_khz;
|
u16 dtv7_if_freq_khz;
|
||||||
@@ -62,6 +63,13 @@ struct tda10048_config {
|
|||||||
|
|
||||||
/* Disable I2C gate access */
|
/* Disable I2C gate access */
|
||||||
u8 disable_gate_access;
|
u8 disable_gate_access;
|
||||||
|
|
||||||
|
bool no_firmware;
|
||||||
|
|
||||||
|
bool set_pll;
|
||||||
|
u8 pll_m;
|
||||||
|
u8 pll_p;
|
||||||
|
u8 pll_n;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(CONFIG_DVB_TDA10048) || \
|
#if defined(CONFIG_DVB_TDA10048) || \
|
||||||
|
Reference in New Issue
Block a user