Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c9f88aa9 authored by Jose Alberto Reguero's avatar Jose Alberto Reguero Committed by Mauro Carvalho Chehab
Browse files

[media] ttusb2: add support for the dvb-t part of CT-3650 v3

parent 84b27148
Loading
Loading
Loading
Loading
+77 −13
Original line number Original line Diff line number Diff line
@@ -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,


+25 −12
Original line number Original line Diff line number Diff line
@@ -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);


+8 −0
Original line number Original line Diff line number Diff line
@@ -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) || \