summaryrefslogtreecommitdiff
path: root/linux/drivers/media/dvb/ttpci
diff options
context:
space:
mode:
authorAndrew de Quincy <devnull@localhost>2004-10-28 17:37:07 +0000
committerAndrew de Quincy <devnull@localhost>2004-10-28 17:37:07 +0000
commit25da23146538519f0f644671c49868bfb560740a (patch)
tree7987970be2d5e86492325711d234ff59319f2685 /linux/drivers/media/dvb/ttpci
parentdcc0614123e60b1b01ed67850ebd22a517d8c086 (diff)
downloadmediapointer-dvb-s2-25da23146538519f0f644671c49868bfb560740a.tar.gz
mediapointer-dvb-s2-25da23146538519f0f644671c49868bfb560740a.tar.bz2
Imported FE_REFACTORING to HEAD
Diffstat (limited to 'linux/drivers/media/dvb/ttpci')
-rw-r--r--linux/drivers/media/dvb/ttpci/Kconfig17
-rw-r--r--linux/drivers/media/dvb/ttpci/Makefile2
-rw-r--r--linux/drivers/media/dvb/ttpci/av7110.c618
-rw-r--r--linux/drivers/media/dvb/ttpci/av7110.h19
-rw-r--r--linux/drivers/media/dvb/ttpci/budget-av.c344
-rw-r--r--linux/drivers/media/dvb/ttpci/budget-ci.c384
-rw-r--r--linux/drivers/media/dvb/ttpci/budget-core.c29
-rw-r--r--linux/drivers/media/dvb/ttpci/budget-patch.c286
-rw-r--r--linux/drivers/media/dvb/ttpci/budget.c412
-rw-r--r--linux/drivers/media/dvb/ttpci/budget.h5
10 files changed, 1868 insertions, 248 deletions
diff --git a/linux/drivers/media/dvb/ttpci/Kconfig b/linux/drivers/media/dvb/ttpci/Kconfig
index cf84d6633..99a230dc5 100644
--- a/linux/drivers/media/dvb/ttpci/Kconfig
+++ b/linux/drivers/media/dvb/ttpci/Kconfig
@@ -4,6 +4,11 @@ config DVB_AV7110
select FW_LOADER
select VIDEO_DEV
select VIDEO_SAA7146_VV
+ select DVB_VES1820
+ select DVB_VES1X93
+ select DVB_STV0299
+ select DVB_TDA8083
+ select DVB_SP8870
help
Support for SAA7146 and AV7110 based DVB cards as produced
by Fujitsu-Siemens, Technotrend, Hauppauge and others.
@@ -53,6 +58,12 @@ config DVB_BUDGET
tristate "Budget cards"
depends on DVB_CORE && PCI
select VIDEO_SAA7146
+ select DVB_STV0299
+ select DVB_VES1X93
+ select DVB_VES1820
+ select DVB_L64781
+ select DVB_TDA8083
+ select DVB_TDA10021
help
Support for simple SAA7146 based DVB cards
(so called Budget- or Nova-PCI cards) without onboard
@@ -67,6 +78,8 @@ config DVB_BUDGET_CI
tristate "Budget cards with onboard CI connector"
depends on DVB_CORE && PCI
select VIDEO_SAA7146
+ select DVB_STV0299
+ select DVB_TDA1004X
help
Support for simple SAA7146 based DVB cards
(so called Budget- or Nova-PCI cards) without onboard
@@ -85,6 +98,7 @@ config DVB_BUDGET_AV
depends on DVB_CORE && PCI
select VIDEO_DEV
select VIDEO_SAA7146_VV
+ select DVB_STV0299
help
Support for simple SAA7146 based DVB cards
(so called Budget- or Nova-PCI cards) without onboard
@@ -99,6 +113,9 @@ config DVB_BUDGET_PATCH
tristate "AV7110 cards with Budget Patch"
depends on DVB_CORE && DVB_BUDGET
select DVB_AV7110
+ select DVB_STV0299
+ select DVB_VES1X93
+ select DVB_TDA8083
help
Support for Budget Patch (full TS) modification on
SAA7146+AV7110 based cards (DVB-S cards). This
diff --git a/linux/drivers/media/dvb/ttpci/Makefile b/linux/drivers/media/dvb/ttpci/Makefile
index 043468a1d..825ab1c38 100644
--- a/linux/drivers/media/dvb/ttpci/Makefile
+++ b/linux/drivers/media/dvb/ttpci/Makefile
@@ -11,7 +11,7 @@ obj-$(CONFIG_DVB_BUDGET_CI) += budget-core.o budget-ci.o ttpci-eeprom.o
obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-core.o budget-patch.o ttpci-eeprom.o
obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o ttpci-eeprom.o
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
+EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
hostprogs-y := fdump
diff --git a/linux/drivers/media/dvb/ttpci/av7110.c b/linux/drivers/media/dvb/ttpci/av7110.c
index 13cd71006..a1da2a5b7 100644
--- a/linux/drivers/media/dvb/ttpci/av7110.c
+++ b/linux/drivers/media/dvb/ttpci/av7110.c
@@ -67,6 +67,7 @@
#include "av7110_ca.h"
#include "av7110_ipack.h"
+
int av7110_debug;
static int vidmode = CVBS_RGB_OUT;
@@ -96,6 +97,16 @@ static void restart_feeds(struct av7110 *av7110);
int av7110_num = 0;
+
+#define FE_FUNC_OVERRIDE(fe_func, av7110_copy, av7110_func) \
+{\
+ if (fe_func != NULL) { \
+ av7110_copy = fe_func; \
+ fe_func = av7110_func; \
+ } \
+}
+
+
static void init_av7110_av(struct av7110 *av7110)
{
struct saa7146_dev *dev=av7110->dev;
@@ -1090,71 +1101,43 @@ static int dvb_get_stc(struct dmx_demux *demux, unsigned int num,
* SEC device file operations
******************************************************************************/
-static int av7110_diseqc_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg)
-{
- struct av7110 *av7110 = fe->before_after_data;
- dprintk(4, "%p\n", av7110);
+static int av7110_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+ struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
- switch (cmd) {
- case FE_SET_TONE:
- switch ((fe_sec_tone_mode_t) arg) {
- case SEC_TONE_ON:
- Set22K(av7110, 1);
- break;
- case SEC_TONE_OFF:
- Set22K(av7110, 0);
- break;
- default:
- return -EINVAL;
- };
+ switch (tone) {
+ case SEC_TONE_ON:
+ Set22K(av7110, 1);
break;
- case FE_DISEQC_SEND_MASTER_CMD:
- {
- struct dvb_diseqc_master_cmd *cmd = arg;
- av7110_diseqc_send(av7110, cmd->msg_len, cmd->msg, -1);
- break;
- }
-
- case FE_DISEQC_SEND_BURST:
- av7110_diseqc_send(av7110, 0, NULL, (unsigned long) arg);
+ case SEC_TONE_OFF:
+ Set22K(av7110, 0);
break;
default:
- return -EOPNOTSUPP;
- };
+ return -EINVAL;
+ }
return 0;
}
-
-static void av7110_before_after_tune(fe_status_t s, void *data)
+static int av7110_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
{
- struct av7110 *av7110 = data;
-
- dprintk(4, "%p\n", av7110);
+ struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
- av7110->fe_synced = (s & FE_HAS_LOCK) ? 1 : 0;
+ av7110_diseqc_send(av7110, cmd->msg_len, cmd->msg, -1);
- if (av7110->playing)
- return;
+ return 0;
+}
- if (down_interruptible(&av7110->pid_mutex))
- return;
+static int av7110_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
+{
+ struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
- if (av7110->fe_synced) {
- SetPIDs(av7110, av7110->pids[DMX_PES_VIDEO],
- av7110->pids[DMX_PES_AUDIO],
- av7110->pids[DMX_PES_TELETEXT], 0,
- av7110->pids[DMX_PES_PCR]);
- av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);
- } else {
- SetPIDs(av7110, 0, 0, 0, 0, 0);
- av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, FlushTSQueue, 0);
- }
+ av7110_diseqc_send(av7110, 0, NULL, minicmd);
- up(&av7110->pid_mutex);
+ return 0;
}
@@ -1170,15 +1153,6 @@ static int av7110_register(struct av7110 *av7110)
av7110->registered = 1;
- dvb_add_frontend_notifier (av7110->dvb_adapter,
- av7110_before_after_tune, av7110);
-
- /**
- * init DiSEqC stuff
- */
- dvb_add_frontend_ioctls (av7110->dvb_adapter,
- av7110_diseqc_ioctl, NULL, av7110);
-
dvbdemux->priv = (void *) av7110;
for (i = 0; i < 32; i++)
@@ -1252,11 +1226,7 @@ static void dvb_unregister(struct av7110 *av7110)
dvb_dmxdev_release(&av7110->dmxdev);
dvb_dmx_release(&av7110->demux);
- dvb_remove_frontend_notifier (av7110->dvb_adapter,
- av7110_before_after_tune);
- dvb_remove_frontend_ioctls (av7110->dvb_adapter,
- av7110_diseqc_ioctl, NULL);
-
+ if (av7110->fe != NULL) dvb_unregister_frontend(av7110->fe);
dvb_unregister_device(av7110->osd_dev);
av7110_av_unregister(av7110);
av7110_ca_unregister(av7110);
@@ -1407,28 +1377,470 @@ static int get_firmware(struct av7110* av7110)
#endif
-static int client_register(struct i2c_client *client)
+static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
- struct saa7146_dev *dev = (struct saa7146_dev*)i2c_get_adapdata(client->adapter);
- struct av7110 *av7110 = (struct av7110*)dev->ext_priv;
+ struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+ u8 pwr = 0;
+ u8 buf[4];
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+ u32 div = (params->frequency + 479500) / 125;
+
+ if (params->frequency > 2000000) pwr = 3;
+ else if (params->frequency > 1800000) pwr = 2;
+ else if (params->frequency > 1600000) pwr = 1;
+ else if (params->frequency > 1200000) pwr = 0;
+ else if (params->frequency >= 1100000) pwr = 1;
+ else pwr = 2;
+
+ buf[0] = (div >> 8) & 0x7f;
+ buf[1] = div & 0xff;
+ buf[2] = ((div & 0x18000) >> 10) | 0x95;
+ buf[3] = (pwr << 6) | 0x30;
+
+ // NOTE: since we're using a prescaler of 2, we set the
+ // divisor frequency to 62.5kHz and divide by 125 above
+
+ if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1)
+ return -EIO;
+ return 0;
+}
+
+static struct ves1x93_config alps_bsrv2_config = {
+ .demod_address = 0x08,
+ .xin = 90100000UL,
+ .invert_pwm = 0,
+ .pll_set = alps_bsrv2_pll_set,
+};
+
+
+static u8 alps_bsru6_inittab[] = {
+ 0x01, 0x15,
+ 0x02, 0x30,
+ 0x03, 0x00,
+ 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+ 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */
+ 0x06, 0x40, /* DAC not used, set to high impendance mode */
+ 0x07, 0x00, /* DAC LSB */
+ 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */
+ 0x09, 0x00, /* FIFO */
+ 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
+ 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */
+ 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
+ 0x10, 0x3f, // AGC2 0x3d
+ 0x11, 0x84,
+ 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on
+ 0x15, 0xc9, // lock detector threshold
+ 0x16, 0x00,
+ 0x17, 0x00,
+ 0x18, 0x00,
+ 0x19, 0x00,
+ 0x1a, 0x00,
+ 0x1f, 0x50,
+ 0x20, 0x00,
+ 0x21, 0x00,
+ 0x22, 0x00,
+ 0x23, 0x00,
+ 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0
+ 0x29, 0x1e, // 1/2 threshold
+ 0x2a, 0x14, // 2/3 threshold
+ 0x2b, 0x0f, // 3/4 threshold
+ 0x2c, 0x09, // 5/6 threshold
+ 0x2d, 0x05, // 7/8 threshold
+ 0x2e, 0x01,
+ 0x31, 0x1f, // test all FECs
+ 0x32, 0x19, // viterbi and synchro search
+ 0x33, 0xfc, // rs control
+ 0x34, 0x93, // error control
+ 0x0f, 0x52,
+ 0xff, 0xff
+};
+
+static int alps_bsru6_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
+{
+ u8 aclk = 0;
+ u8 bclk = 0;
+
+ if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
+ else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
+ else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
+ else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
+ else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
+ else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
+
+ stv0299_writereg (fe, 0x13, aclk);
+ stv0299_writereg (fe, 0x14, bclk);
+ stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff);
+ stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff);
+ stv0299_writereg (fe, 0x21, (ratio ) & 0xf0);
- /* fixme: check for "type" (ie. frontend type) */
- if (client->driver->command)
- return client->driver->command(client, FE_REGISTER, av7110->dvb_adapter);
return 0;
}
-static int client_unregister(struct i2c_client *client)
+static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
- struct saa7146_dev *dev = (struct saa7146_dev*)i2c_get_adapdata(client->adapter);
- struct av7110 *av7110 = (struct av7110*)dev->ext_priv;
+ struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+ int ret;
+ u8 data[4];
+ u32 div;
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+ if ((params->frequency < 950000) || (params->frequency > 2150000))
+ return -EINVAL;
+
+ div = (params->frequency + (125 - 1)) / 125; // round correctly
+ data[0] = (div >> 8) & 0x7f;
+ data[1] = div & 0xff;
+ data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
+ data[3] = 0xC4;
+
+ if (params->frequency > 1530000) data[3] = 0xc0;
+
+ ret = i2c_transfer (&av7110->i2c_adap, &msg, 1);
+ if (ret != 1)
+ return -EIO;
+ return 0;
+}
+
+static struct stv0299_config alps_bsru6_config = {
+
+ .demod_address = 0x68,
+ .inittab = alps_bsru6_inittab,
+ .mclk = 88000000UL,
+ .invert = 1,
+ .enhanced_tuning = 0,
+ .skip_reinit = 0,
+ .lock_output = STV0229_LOCKOUTPUT_1,
+ .volt13_op0_op1 = STV0299_VOLT13_OP1,
+ .min_delay_ms = 100,
+ .set_symbol_rate = alps_bsru6_set_symbol_rate,
+ .pll_set = alps_bsru6_pll_set,
+};
+
+
+
+static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+ u32 div;
+ u8 data[4];
+ struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) };
+
+ div = (params->frequency + 35937500 + 31250) / 62500;
+
+ data[0] = (div >> 8) & 0x7f;
+ data[1] = div & 0xff;
+ data[2] = 0x85 | ((div >> 10) & 0x60);
+ data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81);
+
+ if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1)
+ return -EIO;
+ return 0;
+}
+
+static struct ves1820_config alps_tdbe2_config = {
+ .demod_address = 0x09,
+ .xin = 57840000UL,
+ .invert = 1,
+ .selagc = VES1820_SELAGC_SIGNAMPERR,
+ .pll_set = alps_tdbe2_pll_set,
+};
+
+
+
+
+static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+ u32 div;
+ u8 data[4];
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+ div = params->frequency / 125;
+ data[0] = (div >> 8) & 0x7f;
+ data[1] = div & 0xff;
+ data[2] = 0x8e;
+ data[3] = 0x00;
+
+ if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1)
+ return -EIO;
+ return 0;
+}
+
+static struct tda8083_config grundig_29504_451_config = {
+ .demod_address = 0x68,
+ .pll_set = grundig_29504_451_pll_set,
+};
+
+
+
+static int philips_cd1516_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+ u32 div;
+ u32 f = params->frequency;
+ u8 data[4];
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+ div = (f + 36125000 + 31250) / 62500;
+
+ data[0] = (div >> 8) & 0x7f;
+ data[1] = div & 0xff;
+ data[2] = 0x8e;
+ data[3] = (f < 174000000 ? 0xa1 : f < 470000000 ? 0x92 : 0x34);
+
+ if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1)
+ return -EIO;
+ return 0;
+}
+
+static struct ves1820_config philips_cd1516_config = {
+ .demod_address = 0x09,
+ .xin = 57840000UL,
+ .invert = 1,
+ .selagc = VES1820_SELAGC_SIGNAMPERR,
+ .pll_set = philips_cd1516_pll_set,
+};
+
+
+
+static int alps_tdlb7_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+ u32 div, pwr;
+ u8 data[4];
+ struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = sizeof(data) };
+
+ div = (params->frequency + 36200000) / 166666;
+
+ if (params->frequency <= 782000000)
+ pwr = 1;
+ else
+ pwr = 2;
+
+ data[0] = (div >> 8) & 0x7f;
+ data[1] = div & 0xff;
+ data[2] = 0x85;
+ data[3] = pwr << 6;
- /* fixme: check for "type" (ie. frontend type) */
- if (client->driver->command)
- return client->driver->command(client, FE_UNREGISTER, av7110->dvb_adapter);
+ if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1)
+ return -EIO;
return 0;
}
+static int alps_tdlb7_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
+{
+ struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+
+ return request_firmware(fw, name, &av7110->dev->pci->dev);
+}
+
+static struct sp8870_config alps_tdlb7_config = {
+
+ .demod_address = 0x71,
+ .pll_set = alps_tdlb7_pll_set,
+ .request_firmware = alps_tdlb7_request_firmware,
+};
+
+
+static void av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status)
+{
+ msleep (50);
+
+ av7110->fe_synced = (status & FE_HAS_LOCK) ? 1 : 0;
+
+ if (av7110->playing)
+ return;
+
+ if (down_interruptible(&av7110->pid_mutex))
+ return;
+
+ if (av7110->fe_synced) {
+ SetPIDs(av7110, av7110->pids[DMX_PES_VIDEO],
+ av7110->pids[DMX_PES_AUDIO],
+ av7110->pids[DMX_PES_TELETEXT], 0,
+ av7110->pids[DMX_PES_PCR]);
+ av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);
+ } else {
+ SetPIDs(av7110, 0, 0, 0, 0, 0);
+ av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, FlushTSQueue, 0);
+ }
+
+ av7110->fe_status = status;
+ up(&av7110->pid_mutex);
+}
+
+static int av7110_fe_init(struct dvb_frontend* fe)
+{
+ struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+
+ av7110_fe_lock_fix(av7110, 0);
+ return av7110->fe_init(fe);
+}
+
+static int av7110_fe_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+ struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+ int ret;
+
+ /* call the real implementation */
+ ret = av7110->fe_read_status(fe, status);
+ if (ret)
+ return ret;
+
+ if (((*status ^ av7110->fe_status) & FE_HAS_LOCK) && (*status & FE_HAS_LOCK)) {
+ av7110_fe_lock_fix(av7110, *status);
+ }
+
+ return 0;
+}
+
+static int av7110_fe_diseqc_reset_overload(struct dvb_frontend* fe)
+{
+ struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+
+ av7110_fe_lock_fix(av7110, 0);
+ return av7110->fe_diseqc_reset_overload(fe);
+}
+
+static int av7110_fe_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
+{
+ struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+
+ av7110_fe_lock_fix(av7110, 0);
+ return av7110->fe_diseqc_send_master_cmd(fe, cmd);
+}
+
+static int av7110_fe_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
+{
+ struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+
+ av7110_fe_lock_fix(av7110, 0);
+ return av7110->fe_diseqc_send_burst(fe, minicmd);
+}
+
+static int av7110_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+ struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+
+ av7110_fe_lock_fix(av7110, 0);
+ return av7110->fe_set_tone(fe, tone);
+}
+
+static int av7110_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+ struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+
+ av7110_fe_lock_fix(av7110, 0);
+ return av7110->fe_set_voltage(fe, voltage);
+}
+
+static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, unsigned int cmd)
+{
+ struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
+
+ av7110_fe_lock_fix(av7110, 0);
+ return av7110->fe_dishnetwork_send_legacy_command(fe, cmd);
+}
+
+static u8 read_pwm(struct av7110* av7110)
+{
+ u8 b = 0xff;
+ u8 pwm;
+ struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 },
+ { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} };
+
+ if ((i2c_transfer(&av7110->i2c_adap, msg, 2) != 2) || (pwm == 0xff))
+ pwm = 0x48;
+
+ return pwm;
+}
+
+static void frontend_init(struct av7110 *av7110)
+{
+ if (av7110->dev->pci->subsystem_vendor == 0x110a) {
+ switch(av7110->dev->pci->subsystem_device) {
+ case 0x0000: // Fujitsu/Siemens DVB-Cable (ves1820/Philips CD1516(??))
+ av7110->fe = ves1820_attach(&philips_cd1516_config, &av7110->i2c_adap, read_pwm(av7110));
+ if (av7110->fe)
+ break;
+ break;
+ }
+
+ } else if (av7110->dev->pci->subsystem_vendor == 0x13c2) {
+ switch(av7110->dev->pci->subsystem_device) {
+ case 0x0000: // Hauppauge/TT WinTV DVB-S rev1.X
+ case 0x0003: // Hauppauge/TT WinTV Nexus-S Rev 2.X
+ case 0x1002: // Hauppauge/TT WinTV DVB-S rev1.3SE
+
+ // try the ALPS BSRV2 first of all
+ av7110->fe = ves1x93_attach(&alps_bsrv2_config, &av7110->i2c_adap);
+ if (av7110->fe) {
+ av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+ av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
+ av7110->fe->ops->set_tone = av7110_set_tone;
+ break;
+ }
+
+ // try the ALPS BSRU6 now
+ av7110->fe = stv0299_attach(&alps_bsru6_config, &av7110->i2c_adap);
+ if (av7110->fe) {
+ av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+ av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
+ av7110->fe->ops->set_tone = av7110_set_tone;
+ break;
+ }
+
+ // Try the grundig 29504-451
+ av7110->fe = tda8083_attach(&grundig_29504_451_config, &av7110->i2c_adap);
+ if (av7110->fe) {
+ av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+ av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
+ av7110->fe->ops->set_tone = av7110_set_tone;
+ break;
+ }
+ break;
+
+ case 0x0001: // Hauppauge/TT Nexus-T premium rev1.X
+
+ // ALPS TDLB7
+ av7110->fe = sp8870_attach(&alps_tdlb7_config, &av7110->i2c_adap);
+ if (av7110->fe)
+ break;
+ break;
+
+ case 0x0002: // Hauppauge/TT DVB-C premium rev2.X
+
+ av7110->fe = ves1820_attach(&alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110));
+ if (av7110->fe)
+ break;
+ break;
+ }
+ }
+
+ if (av7110->fe == NULL) {
+ printk("dvb-ttpci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
+ av7110->dev->pci->vendor,
+ av7110->dev->pci->device,
+ av7110->dev->pci->subsystem_vendor,
+ av7110->dev->pci->subsystem_device);
+ } else {
+ FE_FUNC_OVERRIDE(av7110->fe->ops->init, av7110->fe_init, av7110_fe_init);
+ FE_FUNC_OVERRIDE(av7110->fe->ops->read_status, av7110->fe_read_status, av7110_fe_read_status);
+ FE_FUNC_OVERRIDE(av7110->fe->ops->diseqc_reset_overload, av7110->fe_diseqc_reset_overload, av7110_fe_diseqc_reset_overload);
+ FE_FUNC_OVERRIDE(av7110->fe->ops->diseqc_send_master_cmd, av7110->fe_diseqc_send_master_cmd, av7110_fe_diseqc_send_master_cmd);
+ FE_FUNC_OVERRIDE(av7110->fe->ops->diseqc_send_burst, av7110->fe_diseqc_send_burst, av7110_fe_diseqc_send_burst);
+ FE_FUNC_OVERRIDE(av7110->fe->ops->set_tone, av7110->fe_set_tone, av7110_fe_set_tone);
+ FE_FUNC_OVERRIDE(av7110->fe->ops->set_voltage, av7110->fe_set_voltage, av7110_fe_set_voltage;)
+ FE_FUNC_OVERRIDE(av7110->fe->ops->dishnetwork_send_legacy_command, av7110->fe_dishnetwork_send_legacy_command, av7110_fe_dishnetwork_send_legacy_command);
+ if (dvb_register_frontend(av7110->dvb_adapter, av7110->fe)) {
+ printk("av7110: Frontend registration failed!\n");
+ if (av7110->fe->ops->release)
+ av7110->fe->ops->release(av7110->fe);
+ av7110->fe = NULL;
+ }
+ }
+}
+
static int av7110_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *pci_ext)
{
struct av7110 *av7110 = NULL;
@@ -1454,20 +1866,16 @@ static int av7110_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_d
}
dvb_register_adapter(&av7110->dvb_adapter, av7110->card_name, THIS_MODULE);
-
+
/* the Siemens DVB needs this if you want to have the i2c chips
get recognized before the main driver is fully loaded */
saa7146_write(dev, GPIO_CTRL, 0x500000);
- av7110->i2c_adap = (struct i2c_adapter) {
- .client_register = client_register,
- .client_unregister = client_unregister,
#ifdef I2C_ADAP_CLASS_TV_DIGITAL
- .class = I2C_ADAP_CLASS_TV_DIGITAL,
+ av7110->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL;
#else
- .class = I2C_CLASS_TV_DIGITAL,
+ av7110->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
#endif
- };
strlcpy(av7110->i2c_adap.name, pci_ext->ext_priv, sizeof(av7110->i2c_adap.name));
saa7146_i2c_adapter_prepare(dev, &av7110->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120); /* 275 kHz */
@@ -1566,6 +1974,9 @@ static int av7110_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_d
if (ret)
goto err3;
+ av7110->dvb_adapter->priv = av7110;
+ frontend_init(av7110);
+
printk(KERN_INFO "dvb-ttpci: found av7110-%d.\n", av7110_num);
av7110->device_initialized = 1;
av7110_num++;
@@ -1662,33 +2073,28 @@ static struct saa7146_pci_extension_data x_var = { \
.ext_priv = x_name, \
.ext = &av7110_extension }
-MAKE_AV7110_INFO(fs_1_5, "Siemens cable card PCI rev1.5");
-MAKE_AV7110_INFO(fs_1_3, "Siemens/Technotrend/Hauppauge PCI rev1.3");
-MAKE_AV7110_INFO(tt_1_6, "Technotrend/Hauppauge PCI rev1.3 or 1.6");
-MAKE_AV7110_INFO(tt_2_1, "Technotrend/Hauppauge PCI rev2.1 or 2.2");
-MAKE_AV7110_INFO(tt_t, "Technotrend/Hauppauge PCI DVB-T");
-MAKE_AV7110_INFO(unkwn0, "Technotrend/Hauppauge PCI rev?(unknown0)?");
-MAKE_AV7110_INFO(unkwn1, "Technotrend/Hauppauge PCI rev?(unknown1)?");
-MAKE_AV7110_INFO(unkwn2, "Technotrend/Hauppauge PCI rev?(unknown2)?");
-MAKE_AV7110_INFO(nexus, "Technotrend/Hauppauge Nexus PCI DVB-S");
-MAKE_AV7110_INFO(dvboc11,"Octal/Technotrend DVB-C for iTV");
+MAKE_AV7110_INFO(tts_1_X, "Technotrend/Hauppauge WinTV DVB-S rev1.X");
+MAKE_AV7110_INFO(ttt_1_X, "Technotrend/Hauppauge WinTV DVB-T rev1.X");
+MAKE_AV7110_INFO(ttc_2_X, "Technotrend/Hauppauge WinTV DVB-C rev2.X");
+MAKE_AV7110_INFO(tts_2_X, "Technotrend/Hauppauge WinTV Nexus-S rev2.X");
+MAKE_AV7110_INFO(tts_1_3se, "Technotrend/Hauppauge WinTV Nexus-S rev1.3");
+MAKE_AV7110_INFO(fsc, "Fujitsu Siemens DVB-C");
static struct pci_device_id pci_tbl[] = {
- MAKE_EXTENSION_PCI(fs_1_5, 0x110a, 0xffff),
- MAKE_EXTENSION_PCI(fs_1_5, 0x110a, 0x0000),
- MAKE_EXTENSION_PCI(fs_1_3, 0x13c2, 0x0000),
- MAKE_EXTENSION_PCI(unkwn0, 0x13c2, 0x1002),
- MAKE_EXTENSION_PCI(tt_1_6, 0x13c2, 0x0001),
- MAKE_EXTENSION_PCI(tt_2_1, 0x13c2, 0x0002),
- MAKE_EXTENSION_PCI(tt_2_1, 0x13c2, 0x0003),
- MAKE_EXTENSION_PCI(tt_2_1, 0x13c2, 0x0004),
- MAKE_EXTENSION_PCI(tt_1_6, 0x13c2, 0x0006),
- MAKE_EXTENSION_PCI(tt_t, 0x13c2, 0x0008),
- MAKE_EXTENSION_PCI(tt_2_1, 0x13c2, 0x1102),
- MAKE_EXTENSION_PCI(unkwn1, 0xffc2, 0x0000),
- MAKE_EXTENSION_PCI(unkwn2, 0x00a1, 0x00a1),
- MAKE_EXTENSION_PCI(nexus, 0x00a1, 0xa1a0),
- MAKE_EXTENSION_PCI(dvboc11,0x13c2, 0x000a),
+ MAKE_EXTENSION_PCI(tts_1_X, 0x13c2, 0x0000),
+ MAKE_EXTENSION_PCI(ttt_1_X, 0x13c2, 0x0001),
+ MAKE_EXTENSION_PCI(ttc_2_X, 0x13c2, 0x0002),
+ MAKE_EXTENSION_PCI(tts_2_X, 0x13c2, 0x0003),
+ MAKE_EXTENSION_PCI(tts_1_3se, 0x13c2, 0x1002),
+ MAKE_EXTENSION_PCI(fsc, 0x110a, 0x0000),
+
+/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0004), UNDEFINED CARD */ // Galaxis DVB PC-Sat-Carte
+/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0005), UNDEFINED CARD */ // Technisat SkyStar1
+/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0006), UNDEFINED CARD */ // TT/Hauppauge WinTV Nexus-S v????
+/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0008), UNDEFINED CARD */ // TT/Hauppauge WinTV DVB-T v????
+/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0009), UNDEFINED CARD */ // TT/Hauppauge WinTV Nexus-CA v????
+/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x000a), UNDEFINED CARD */ // TT/Hauppauge WinTV Nexus-CA v????
+
{
.vendor = 0,
}
diff --git a/linux/drivers/media/dvb/ttpci/av7110.h b/linux/drivers/media/dvb/ttpci/av7110.h
index abdc8ab8a..5d2da07f8 100644
--- a/linux/drivers/media/dvb/ttpci/av7110.h
+++ b/linux/drivers/media/dvb/ttpci/av7110.h
@@ -24,9 +24,17 @@
#include "dvb_filter.h"
#include "dvb_net.h"
#include "dvb_ringbuffer.h"
+#include "dvb_frontend.h"
+#include "ves1820.h"
+#include "ves1x93.h"
+#include "stv0299.h"
+#include "tda8083.h"
+#include "sp8870.h"
+
#include <media/saa7146_vv.h>
+
extern int av7110_debug;
#define dprintk(level,args...) \
@@ -217,6 +225,17 @@ struct av7110 {
unsigned char *bin_root;
unsigned long size_root;
+
+ struct dvb_frontend* fe;
+ fe_status_t fe_status;
+ int (*fe_init)(struct dvb_frontend* fe);
+ int (*fe_read_status)(struct dvb_frontend* fe, fe_status_t* status);
+ int (*fe_diseqc_reset_overload)(struct dvb_frontend* fe);
+ int (*fe_diseqc_send_master_cmd)(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd);
+ int (*fe_diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd);
+ int (*fe_set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone);
+ int (*fe_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
+ int (*fe_dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned int cmd);
};
diff --git a/linux/drivers/media/dvb/ttpci/budget-av.c b/linux/drivers/media/dvb/ttpci/budget-av.c
index 036442e33..28792962d 100644
--- a/linux/drivers/media/dvb/ttpci/budget-av.c
+++ b/linux/drivers/media/dvb/ttpci/budget-av.c
@@ -31,6 +31,9 @@
*/
#include "budget.h"
+#include "stv0299.h"
+#include "tda10021.h"
+#include "tda1004x.h"
#include <media/saa7146_vv.h>
struct budget_av {
@@ -159,6 +162,328 @@ static int saa7113_setinput (struct budget_av *budget_av, int input)
return 0;
}
+
+static int philips_su1278_ty_ci_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
+{
+ u8 aclk = 0;
+ u8 bclk = 0;
+ u8 m1;
+
+ aclk = 0xb5;
+ if (srate < 2000000) bclk = 0x86;
+ else if (srate < 5000000) bclk = 0x89;
+ else if (srate < 15000000) bclk = 0x8f;
+ else if (srate < 45000000) bclk = 0x95;
+
+ m1 = 0x14;
+ if (srate < 4000000) m1 = 0x10;
+
+ stv0299_writereg (fe, 0x13, aclk);
+ stv0299_writereg (fe, 0x14, bclk);
+ stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff);
+ stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff);
+ stv0299_writereg (fe, 0x21, (ratio ) & 0xf0);
+ stv0299_writereg (fe, 0x0f, 0x80 | m1);
+
+ return 0;
+}
+
+static int philips_su1278_ty_ci_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct budget_av* budget_av = (struct budget_av*) fe->dvb->priv;
+ u32 div;
+ u8 buf[4];
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+
+ if ((params->frequency < 950000) || (params->frequency > 2150000)) return -EINVAL;
+
+ div = (params->frequency + (125 - 1)) / 125; // round correctly
+ buf[0] = (div >> 8) & 0x7f;
+ buf[1] = div & 0xff;
+ buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
+ buf[3] = 0x20;
+
+ if (params->u.qpsk.symbol_rate < 4000000) buf[3] |= 1;
+
+ if (params->frequency < 1250000) buf[3] |= 0;
+ else if (params->frequency < 1550000) buf[3] |= 0x40;
+ else if (params->frequency < 2050000) buf[3] |= 0x80;
+ else if (params->frequency < 2150000) buf[3] |= 0xC0;
+
+ if (i2c_transfer (&budget_av->budget.i2c_adap, &msg, 1) != 1) return -EIO;
+ return 0;
+}
+
+static u8 typhoon_cinergy1200s_inittab[] = {
+ 0x01, 0x15,
+ 0x02, 0x30,
+ 0x03, 0x00,
+ 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+ 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */
+ 0x06, 0x40, /* DAC not used, set to high impendance mode */
+ 0x07, 0x00, /* DAC LSB */
+ 0x08, 0x40, /* DiSEqC off */
+ 0x09, 0x00, /* FIFO */
+ 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
+ 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */
+ 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
+ 0x10, 0x3f, // AGC2 0x3d
+ 0x11, 0x84,
+ 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on
+ 0x15, 0xc9, // lock detector threshold
+ 0x16, 0x00,
+ 0x17, 0x00,
+ 0x18, 0x00,
+ 0x19, 0x00,
+ 0x1a, 0x00,
+ 0x1f, 0x50,
+ 0x20, 0x00,
+ 0x21, 0x00,
+ 0x22, 0x00,
+ 0x23, 0x00,
+ 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0
+ 0x29, 0x1e, // 1/2 threshold
+ 0x2a, 0x14, // 2/3 threshold
+ 0x2b, 0x0f, // 3/4 threshold
+ 0x2c, 0x09, // 5/6 threshold
+ 0x2d, 0x05, // 7/8 threshold
+ 0x2e, 0x01,
+ 0x31, 0x1f, // test all FECs
+ 0x32, 0x19, // viterbi and synchro search
+ 0x33, 0xfc, // rs control
+ 0x34, 0x93, // error control
+ 0x0f, 0x92,
+ 0xff, 0xff
+};
+
+static struct stv0299_config typhoon_config = {
+ .demod_address = 0x68,
+ .inittab = typhoon_cinergy1200s_inittab,
+ .mclk = 88000000UL,
+ .invert = 0,
+ .enhanced_tuning = 0,
+ .skip_reinit = 0,
+ .lock_output = STV0229_LOCKOUTPUT_1,
+ .volt13_op0_op1 = STV0299_VOLT13_OP0,
+ .min_delay_ms = 100,
+ .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
+ .pll_set = philips_su1278_ty_ci_pll_set,
+};
+
+
+static struct stv0299_config cinergy_1200s_config = {
+ .demod_address = 0x68,
+ .inittab = typhoon_cinergy1200s_inittab,
+ .mclk = 88000000UL,
+ .invert = 0,
+ .enhanced_tuning = 0,
+ .skip_reinit = 0,
+ .lock_output = STV0229_LOCKOUTPUT_0,
+ .volt13_op0_op1 = STV0299_VOLT13_OP0,
+ .min_delay_ms = 100,
+ .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
+ .pll_set = philips_su1278_ty_ci_pll_set,
+};
+
+
+static int philips_cu1216_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct budget* budget = (struct budget*) fe->dvb->priv;
+ u8 buf[4];
+ struct i2c_msg msg= { .addr=0x60,.flags=0,.buf=buf,.len=sizeof(buf) };
+
+#define TUNER_MUL 62500
+
+ u32 div = (params->frequency + 36125000 + TUNER_MUL/2) / TUNER_MUL;
+
+ buf[0] = (div>>8) & 0x7f;
+ buf[1] = div & 0xff;
+ buf[2] = 0x8e;
+ buf[3] =(params->frequency < 174500000 ? 0xa1 :
+ params->frequency < 454000000 ? 0x92 : 0x34);
+
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+ return 0;
+}
+
+static struct tda10021_config philips_cu1216_config = {
+ .demod_address = 0x0c,
+ .pll_set = philips_cu1216_pll_set,
+};
+
+
+
+
+static int philips_tu1216_pll_init(struct dvb_frontend* fe)
+{
+ struct budget* budget = (struct budget*) fe->dvb->priv;
+ static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab };
+ static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
+ struct i2c_msg tuner_msg = { .addr=0x60, .flags=0, .buf=tu1216_init, .len=sizeof(tu1216_init) };
+
+ // setup PLL configuration
+ if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1) return -EIO;
+ msleep(1);
+
+ // disable the mc44BC374c (do not check for errors)
+ tuner_msg.addr = 0x65;
+ tuner_msg.buf = disable_mc44BC374c;
+ tuner_msg.len = sizeof(disable_mc44BC374c);
+ if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1) {
+ i2c_transfer(&budget->i2c_adap, &tuner_msg, 1);
+ }
+
+ return 0;
+}
+
+static int philips_tu1216_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct budget* budget = (struct budget*) fe->dvb->priv;
+ u8 tuner_buf[4];
+ struct i2c_msg tuner_msg = {.addr=0x60, .flags=0, .buf=tuner_buf, .len=sizeof(tuner_buf) };
+ int tuner_frequency = 0;
+ u8 band, cp, filter;
+
+ // determine charge pump
+ tuner_frequency = params->frequency + 36130000;
+ if (tuner_frequency < 87000000) return -EINVAL;
+ else if (tuner_frequency < 130000000) cp = 3;
+ else if (tuner_frequency < 160000000) cp = 5;
+ else if (tuner_frequency < 200000000) cp = 6;
+ else if (tuner_frequency < 290000000) cp = 3;
+ else if (tuner_frequency < 420000000) cp = 5;
+ else if (tuner_frequency < 480000000) cp = 6;
+ else if (tuner_frequency < 620000000) cp = 3;
+ else if (tuner_frequency < 830000000) cp = 5;
+ else if (tuner_frequency < 895000000) cp = 7;
+ else return -EINVAL;
+
+ // determine band
+ if (params->frequency < 49000000) return -EINVAL;
+ else if (params->frequency < 159000000) band = 1;
+ else if (params->frequency < 444000000) band = 2;
+ else if (params->frequency < 861000000) band = 4;
+ else return -EINVAL;
+
+ // setup PLL filter
+ switch (params->u.ofdm.bandwidth) {
+ case BANDWIDTH_6_MHZ:
+ tda1004x_write_byte(fe, 0x0C, 0);
+ filter = 0;
+ break;
+
+ case BANDWIDTH_7_MHZ:
+ tda1004x_write_byte(fe, 0x0C, 0);
+ filter = 0;
+ break;
+
+ case BANDWIDTH_8_MHZ:
+ tda1004x_write_byte(fe, 0x0C, 0xFF);
+ filter = 1;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ // calculate divisor
+ // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
+ tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000;
+
+ // setup tuner buffer
+ tuner_buf[0] = tuner_frequency >> 8;
+ tuner_buf[1] = tuner_frequency & 0xff;
+ tuner_buf[2] = 0xca;
+ tuner_buf[3] = (cp << 5) | (filter << 3) | band;
+
+ if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1) return -EIO;
+
+ msleep(1);
+ return 0;
+}
+
+static int philips_tu1216_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
+{
+ struct budget* budget = (struct budget*) fe->dvb->priv;
+
+ return request_firmware(fw, name, &budget->dev->pci->dev);
+}
+
+struct tda1004x_config philips_tu1216_config = {
+
+ .demod_address = 0x8,
+ .invert = 1,
+ .pll_init = philips_tu1216_pll_init,
+ .pll_set = philips_tu1216_pll_set,
+ .request_firmware = philips_tu1216_request_firmware,
+};
+
+
+
+
+static u8 read_pwm(struct budget_av* budget_av)
+{
+ u8 b = 0xff;
+ u8 pwm;
+ struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 },
+ { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} };
+
+ if ((i2c_transfer(&budget_av->budget.i2c_adap, msg, 2) != 2) || (pwm == 0xff))
+ pwm = 0x48;
+
+ return pwm;
+}
+
+
+static void frontend_init(struct budget_av *budget_av)
+{
+ switch(budget_av->budget.dev->pci->subsystem_device) {
+ case 0x4f56: // Typhoon/KNC1 DVB-S budget (stv0299/Philips SU1278(tsa5059))
+ budget_av->budget.dvb_frontend = stv0299_attach(&typhoon_config, &budget_av->budget.i2c_adap);
+ if (budget_av->budget.dvb_frontend != NULL) {
+ break;
+ }
+ break;
+
+ case 0x1154: // TerraTec Cinergy 1200 DVB-S (stv0299/Philips SU1278(tsa5059))
+ budget_av->budget.dvb_frontend = stv0299_attach(&cinergy_1200s_config, &budget_av->budget.i2c_adap);
+ if (budget_av->budget.dvb_frontend != NULL) {
+ break;
+ }
+ break;
+
+ case 0x1156: // Terratec Cinergy 1200 DVB-C (tda10021/Philips CU1216(tua6034))
+ budget_av->budget.dvb_frontend = tda10021_attach(&philips_cu1216_config, &budget_av->budget.i2c_adap, read_pwm(budget_av));
+ if (budget_av->budget.dvb_frontend) {
+ break;
+ }
+ break;
+
+ case 0x1157: // Terratec Cinergy 1200 DVB-T (tda10046/Philips TU1216(tda6651tt))
+ budget_av->budget.dvb_frontend = tda10046_attach(&philips_tu1216_config, &budget_av->budget.i2c_adap);
+ if (budget_av->budget.dvb_frontend) {
+ break;
+ }
+ break;
+ }
+
+ if (budget_av->budget.dvb_frontend == NULL) {
+ printk("budget_av: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
+ budget_av->budget.dev->pci->vendor,
+ budget_av->budget.dev->pci->device,
+ budget_av->budget.dev->pci->subsystem_vendor,
+ budget_av->budget.dev->pci->subsystem_device);
+ } else {
+ if (dvb_register_frontend(budget_av->budget.dvb_adapter, budget_av->budget.dvb_frontend)) {
+ printk("budget-av: Frontend registration failed!\n");
+ if (budget_av->budget.dvb_frontend->ops->release)
+ budget_av->budget.dvb_frontend->ops->release(budget_av->budget.dvb_frontend);
+ budget_av->budget.dvb_frontend = NULL;
+ }
+ }
+}
+
+
static int budget_av_detach (struct saa7146_dev *dev)
{
struct budget_av *budget_av = (struct budget_av*) dev->ext_priv;
@@ -173,7 +498,7 @@ static int budget_av_detach (struct saa7146_dev *dev)
saa7146_unregister_device (&budget_av->vd, dev);
}
-
+ if (budget_av->budget.dvb_frontend != NULL) dvb_unregister_frontend(budget_av->budget.dvb_frontend);
err = ttpci_budget_deinit (&budget_av->budget);
kfree (budget_av);
@@ -187,16 +512,11 @@ static int budget_av_attach (struct saa7146_dev* dev,
struct saa7146_pci_extension_data *info)
{
struct budget_av *budget_av;
- struct budget_info *bi = info->ext_priv;
u8 *mac;
int err;
dprintk(2, "dev: %p\n", dev);
- if (bi->type != BUDGET_KNC1 && bi->type != BUDGET_CIN1200) {
- return -ENODEV;
- }
-
if (!(budget_av = kmalloc(sizeof(struct budget_av), GFP_KERNEL)))
return -ENOMEM;
@@ -260,6 +580,10 @@ static int budget_av_attach (struct saa7146_dev* dev,
printk("KNC1-%d: MAC addr = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
budget_av->budget.dvb_adapter->num,
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+
+ budget_av->budget.dvb_adapter->priv = budget_av;
+ frontend_init(budget_av);
+
return 0;
}
@@ -343,11 +667,15 @@ static struct saa7146_ext_vv vv_data = {
static struct saa7146_extension budget_extension;
MAKE_BUDGET_INFO(knc1, "KNC1 DVB-S", BUDGET_KNC1);
-MAKE_BUDGET_INFO(cin1200, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200);
+MAKE_BUDGET_INFO(cin1200s, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S);
+MAKE_BUDGET_INFO(cin1200c, "Terratec Cinergy 1200 DVB-C", BUDGET_CIN1200C);
+MAKE_BUDGET_INFO(cin1200t, "Terratec Cinergy 1200 DVB-T", BUDGET_CIN1200T);
static struct pci_device_id pci_tbl [] = {
MAKE_EXTENSION_PCI(knc1, 0x1131, 0x4f56),
- MAKE_EXTENSION_PCI(cin1200, 0x153b, 0x1154),
+ MAKE_EXTENSION_PCI(cin1200s, 0x153b, 0x1154),
+ MAKE_EXTENSION_PCI(cin1200c, 0x153b, 0x1156),
+ MAKE_EXTENSION_PCI(cin1200t, 0x153b, 0x1157),
{
.vendor = 0,
}
diff --git a/linux/drivers/media/dvb/ttpci/budget-ci.c b/linux/drivers/media/dvb/ttpci/budget-ci.c
index c2703e558..bbd1dc0a3 100644
--- a/linux/drivers/media/dvb/ttpci/budget-ci.c
+++ b/linux/drivers/media/dvb/ttpci/budget-ci.c
@@ -39,6 +39,8 @@
#include <linux/spinlock.h>
#include "dvb_ca_en50221.h"
+#include "stv0299.h"
+#include "tda1004x.h"
#define DEBIADDR_IR 0x1234
#define DEBIADDR_CICONTROL 0x0000
@@ -503,12 +505,383 @@ static void budget_ci_irq (struct saa7146_dev *dev, u32 *isr)
tasklet_schedule (&budget_ci->ciintf_irq_tasklet);
}
+
+static u8 alps_bsru6_inittab[] = {
+ 0x01, 0x15,
+ 0x02, 0x00,
+ 0x03, 0x00,
+ 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+ 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */
+ 0x06, 0x40, /* DAC not used, set to high impendance mode */
+ 0x07, 0x00, /* DAC LSB */
+ 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */
+ 0x09, 0x00, /* FIFO */
+ 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
+ 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */
+ 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
+ 0x10, 0x3f, // AGC2 0x3d
+ 0x11, 0x84,
+ 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on
+ 0x15, 0xc9, // lock detector threshold
+ 0x16, 0x00,
+ 0x17, 0x00,
+ 0x18, 0x00,
+ 0x19, 0x00,
+ 0x1a, 0x00,
+ 0x1f, 0x50,
+ 0x20, 0x00,
+ 0x21, 0x00,
+ 0x22, 0x00,
+ 0x23, 0x00,
+ 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0
+ 0x29, 0x1e, // 1/2 threshold
+ 0x2a, 0x14, // 2/3 threshold
+ 0x2b, 0x0f, // 3/4 threshold
+ 0x2c, 0x09, // 5/6 threshold
+ 0x2d, 0x05, // 7/8 threshold
+ 0x2e, 0x01,
+ 0x31, 0x1f, // test all FECs
+ 0x32, 0x19, // viterbi and synchro search
+ 0x33, 0xfc, // rs control
+ 0x34, 0x93, // error control
+ 0x0f, 0x52,
+ 0xff, 0xff
+};
+
+static int alps_bsru6_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
+{
+ u8 aclk = 0;
+ u8 bclk = 0;
+
+ if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
+ else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
+ else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
+ else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
+ else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
+ else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
+
+ stv0299_writereg (fe, 0x13, aclk);
+ stv0299_writereg (fe, 0x14, bclk);
+ stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff);
+ stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff);
+ stv0299_writereg (fe, 0x21, (ratio ) & 0xf0);
+
+ return 0;
+}
+
+static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct budget_ci* budget_ci = (struct budget_ci*) fe->dvb->priv;
+ u8 buf[4];
+ u32 div;
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+
+ if ((params->frequency < 950000) || (params->frequency > 2150000)) return -EINVAL;
+
+ div = (params->frequency + (125 - 1)) / 125; // round correctly
+ buf[0] = (div >> 8) & 0x7f;
+ buf[1] = div & 0xff;
+ buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
+ buf[3] = 0xC4;
+
+ if (params->frequency > 1530000) buf[3] = 0xc0;
+
+ if (i2c_transfer (&budget_ci->budget.i2c_adap, &msg, 1) != 1) return -EIO;
+ return 0;
+}
+
+static struct stv0299_config alps_bsru6_config = {
+
+ .demod_address = 0x68,
+ .inittab = alps_bsru6_inittab,
+ .mclk = 88000000UL,
+ .invert = 1,
+ .enhanced_tuning = 0,
+ .skip_reinit = 0,
+ .lock_output = STV0229_LOCKOUTPUT_1,
+ .volt13_op0_op1 = STV0299_VOLT13_OP1,
+ .min_delay_ms = 100,
+ .set_symbol_rate = alps_bsru6_set_symbol_rate,
+ .pll_set = alps_bsru6_pll_set,
+};
+
+
+
+
+static u8 philips_su1278_tt_inittab[] = {
+ 0x01, 0x0f,
+ 0x02, 0x30,
+ 0x03, 0x00,
+ 0x04, 0x5b,
+ 0x05, 0x85,
+ 0x06, 0x02,
+ 0x07, 0x00,
+ 0x08, 0x02,
+ 0x09, 0x00,
+ 0x0C, 0x01,
+ 0x0D, 0x81,
+ 0x0E, 0x44,
+ 0x0f, 0x14,
+ 0x10, 0x3c,
+ 0x11, 0x84,
+ 0x12, 0xda,
+ 0x13, 0x97,
+ 0x14, 0x95,
+ 0x15, 0xc9,
+ 0x16, 0x19,
+ 0x17, 0x8c,
+ 0x18, 0x59,
+ 0x19, 0xf8,
+ 0x1a, 0xfe,
+ 0x1c, 0x7f,
+ 0x1d, 0x00,
+ 0x1e, 0x00,
+ 0x1f, 0x50,
+ 0x20, 0x00,
+ 0x21, 0x00,
+ 0x22, 0x00,
+ 0x23, 0x00,
+ 0x28, 0x00,
+ 0x29, 0x28,
+ 0x2a, 0x14,
+ 0x2b, 0x0f,
+ 0x2c, 0x09,
+ 0x2d, 0x09,
+ 0x31, 0x1f,
+ 0x32, 0x19,
+ 0x33, 0xfc,
+ 0x34, 0x93,
+ 0xff, 0xff
+};
+
+static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
+{
+ stv0299_writereg (fe, 0x0e, 0x44);
+ if (srate >= 10000000) {
+ stv0299_writereg (fe, 0x13, 0x97);
+ stv0299_writereg (fe, 0x14, 0x95);
+ stv0299_writereg (fe, 0x15, 0xc9);
+ stv0299_writereg (fe, 0x17, 0x8c);
+ stv0299_writereg (fe, 0x1a, 0xfe);
+ stv0299_writereg (fe, 0x1c, 0x7f);
+ stv0299_writereg (fe, 0x2d, 0x09);
+ } else {
+ stv0299_writereg (fe, 0x13, 0x99);
+ stv0299_writereg (fe, 0x14, 0x8d);
+ stv0299_writereg (fe, 0x15, 0xce);
+ stv0299_writereg (fe, 0x17, 0x43);
+ stv0299_writereg (fe, 0x1a, 0x1d);
+ stv0299_writereg (fe, 0x1c, 0x12);
+ stv0299_writereg (fe, 0x2d, 0x05);
+ }
+ stv0299_writereg (fe, 0x0e, 0x23);
+ stv0299_writereg (fe, 0x0f, 0x94);
+ stv0299_writereg (fe, 0x10, 0x39);
+ stv0299_writereg (fe, 0x15, 0xc9);
+
+ stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff);
+ stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff);
+ stv0299_writereg (fe, 0x21, (ratio ) & 0xf0);
+
+ return 0;
+}
+
+static int philips_su1278_tt_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct budget_ci* budget_ci = (struct budget_ci*) fe->dvb->priv;
+ u32 div;
+ u8 buf[4];
+ struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf) };
+
+ if ((params->frequency < 950000) || (params->frequency > 2150000)) return -EINVAL;
+
+ div = (params->frequency + (500 - 1)) / 500; // round correctly
+ buf[0] = (div >> 8) & 0x7f;
+ buf[1] = div & 0xff;
+ buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2;
+ buf[3] = 0x20;
+
+ if (params->u.qpsk.symbol_rate < 4000000) buf[3] |= 1;
+
+ if (params->frequency < 1250000) buf[3] |= 0;
+ else if (params->frequency < 1550000) buf[3] |= 0x40;
+ else if (params->frequency < 2050000) buf[3] |= 0x80;
+ else if (params->frequency < 2150000) buf[3] |= 0xC0;
+
+ if (i2c_transfer (&budget_ci->budget.i2c_adap, &msg, 1) != 1) return -EIO;
+ return 0;
+}
+
+static struct stv0299_config philips_su1278_tt_config = {
+
+ .demod_address = 0x68,
+ .inittab = philips_su1278_tt_inittab,
+ .mclk = 64000000UL,
+ .invert = 0,
+ .enhanced_tuning = 1,
+ .skip_reinit = 1,
+ .lock_output = STV0229_LOCKOUTPUT_1,
+ .volt13_op0_op1 = STV0299_VOLT13_OP1,
+ .min_delay_ms = 50,
+ .set_symbol_rate = philips_su1278_tt_set_symbol_rate,
+ .pll_set = philips_su1278_tt_pll_set,
+};
+
+
+
+static int philips_tdm1316l_pll_init(struct dvb_frontend* fe)
+{
+ struct budget_ci* budget_ci = (struct budget_ci*) fe->dvb->priv;
+ static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
+ static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
+ struct i2c_msg tuner_msg = { .addr=0x63, .flags=0, .buf=td1316_init, .len=sizeof(td1316_init) };
+
+ // setup PLL configuration
+ if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) return -EIO;
+ msleep(1);
+
+ // disable the mc44BC374c (do not check for errors)
+ tuner_msg.addr = 0x65;
+ tuner_msg.buf = disable_mc44BC374c;
+ tuner_msg.len = sizeof(disable_mc44BC374c);
+ if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) {
+ i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1);
+ }
+
+ return 0;
+}
+
+static int philips_tdm1316l_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct budget_ci* budget_ci = (struct budget_ci*) fe->dvb->priv;
+ u8 tuner_buf[4];
+ struct i2c_msg tuner_msg = {.addr=0x63, .flags=0, .buf=tuner_buf, .len=sizeof(tuner_buf) };
+ int tuner_frequency = 0;
+ u8 band, cp, filter;
+
+ // determine charge pump
+ tuner_frequency = params->frequency + 36130000;
+ if (tuner_frequency < 87000000) return -EINVAL;
+ else if (tuner_frequency < 130000000) cp = 3;
+ else if (tuner_frequency < 160000000) cp = 5;
+ else if (tuner_frequency < 200000000) cp = 6;
+ else if (tuner_frequency < 290000000) cp = 3;
+ else if (tuner_frequency < 420000000) cp = 5;
+ else if (tuner_frequency < 480000000) cp = 6;
+ else if (tuner_frequency < 620000000) cp = 3;
+ else if (tuner_frequency < 830000000) cp = 5;
+ else if (tuner_frequency < 895000000) cp = 7;
+ else return -EINVAL;
+
+ // determine band
+ if (params->frequency < 49000000) return -EINVAL;
+ else if (params->frequency < 159000000) band = 1;
+ else if (params->frequency < 444000000) band = 2;
+ else if (params->frequency < 861000000) band = 4;
+ else return -EINVAL;
+
+ // setup PLL filter and TDA9889
+ switch (params->u.ofdm.bandwidth) {
+ case BANDWIDTH_6_MHZ:
+ tda1004x_write_byte(fe, 0x0C, 0x14);
+ filter = 0;
+ break;
+
+ case BANDWIDTH_7_MHZ:
+ tda1004x_write_byte(fe, 0x0C, 0x80);
+ filter = 0;
+ break;
+
+ case BANDWIDTH_8_MHZ:
+ tda1004x_write_byte(fe, 0x0C, 0x14);
+ filter = 1;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ // calculate divisor
+ // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
+ tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000;
+
+ // setup tuner buffer
+ tuner_buf[0] = tuner_frequency >> 8;
+ tuner_buf[1] = tuner_frequency & 0xff;
+ tuner_buf[2] = 0xca;
+ tuner_buf[3] = (cp << 5) | (filter << 3) | band;
+
+ if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) return -EIO;
+
+ msleep(1);
+ return 0;
+}
+
+static int philips_tdm1316l_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
+{
+ struct budget_ci* budget_ci = (struct budget_ci*) fe->dvb->priv;
+
+ return request_firmware(fw, name, &budget_ci->budget.dev->pci->dev);
+}
+
+struct tda1004x_config philips_tdm1316l_config = {
+
+ .demod_address = 0x8,
+ .invert = 0,
+ .pll_init = philips_tdm1316l_pll_init,
+ .pll_set = philips_tdm1316l_pll_set,
+ .request_firmware = philips_tdm1316l_request_firmware,
+};
+
+
+
+static void frontend_init(struct budget_ci *budget_ci)
+{
+ switch(budget_ci->budget.dev->pci->subsystem_device) {
+ case 0x100c: // Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059))
+ budget_ci->budget.dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget_ci->budget.i2c_adap);
+ if (budget_ci->budget.dvb_frontend) {
+ break;
+ }
+ break;
+
+ case 0x100f: // Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059))
+ budget_ci->budget.dvb_frontend = stv0299_attach(&philips_su1278_tt_config, &budget_ci->budget.i2c_adap);
+ if (budget_ci->budget.dvb_frontend) {
+ break;
+ }
+ break;
+
+ case 0x1011: // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889)
+ budget_ci->budget.dvb_frontend = tda10045_attach(&philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
+ if (budget_ci->budget.dvb_frontend) {
+ break;
+ }
+ break;
+ }
+
+ if (budget_ci->budget.dvb_frontend == NULL) {
+ printk("budget-ci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
+ budget_ci->budget.dev->pci->vendor,
+ budget_ci->budget.dev->pci->device,
+ budget_ci->budget.dev->pci->subsystem_vendor,
+ budget_ci->budget.dev->pci->subsystem_device);
+ } else {
+ if (dvb_register_frontend(budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) {
+ printk("budget-ci: Frontend registration failed!\n");
+ if (budget_ci->budget.dvb_frontend->ops->release)
+ budget_ci->budget.dvb_frontend->ops->release(budget_ci->budget.dvb_frontend);
+ budget_ci->budget.dvb_frontend = NULL;
+ }
+ }
+}
+
static int budget_ci_attach (struct saa7146_dev* dev,
- struct saa7146_pci_extension_data *info)
+ struct saa7146_pci_extension_data *info)
{
struct budget_ci *budget_ci;
int err;
-
+
if (!(budget_ci = kmalloc (sizeof(struct budget_ci), GFP_KERNEL)))
return -ENOMEM;
@@ -531,6 +904,9 @@ static int budget_ci_attach (struct saa7146_dev* dev,
ciintf_init(budget_ci);
+ budget_ci->budget.dvb_adapter->priv = budget_ci;
+ frontend_init(budget_ci);
+
return 0;
}
@@ -541,7 +917,7 @@ static int budget_ci_detach (struct saa7146_dev* dev)
int err;
if (budget_ci->budget.ci_present) ciintf_deinit(budget_ci);
-
+ if (budget_ci->budget.dvb_frontend) dvb_unregister_frontend(budget_ci->budget.dvb_frontend);
err = ttpci_budget_deinit (&budget_ci->budget);
tasklet_kill (&budget_ci->msp430_irq_tasklet);
@@ -578,7 +954,7 @@ static struct saa7146_extension budget_extension = {
.module = THIS_MODULE,
.pci_tbl = &pci_tbl[0],
- .attach = budget_ci_attach,
+ .attach = budget_ci_attach,
.detach = budget_ci_detach,
.irq_mask = MASK_03 | MASK_06 | MASK_10,
diff --git a/linux/drivers/media/dvb/ttpci/budget-core.c b/linux/drivers/media/dvb/ttpci/budget-core.c
index 6bd202b24..7334119a4 100644
--- a/linux/drivers/media/dvb/ttpci/budget-core.c
+++ b/linux/drivers/media/dvb/ttpci/budget-core.c
@@ -257,27 +257,6 @@ static void budget_unregister(struct budget *budget)
dvb_dmx_release(&budget->demux);
}
-/* fixme: can this be unified among all saa7146 based dvb cards? */
-static int client_register(struct i2c_client *client)
-{
- struct saa7146_dev *dev = (struct saa7146_dev*)i2c_get_adapdata(client->adapter);
- struct budget *budget = (struct budget*)dev->ext_priv;
-
- if (client->driver->command)
- return client->driver->command(client, FE_REGISTER, budget->dvb_adapter);
- return 0;
-}
-
-static int client_unregister(struct i2c_client *client)
-{
- struct saa7146_dev *dev = (struct saa7146_dev*)i2c_get_adapdata(client->adapter);
- struct budget *budget = (struct budget*)dev->ext_priv;
-
- if (client->driver->command)
- return client->driver->command(client, FE_UNREGISTER, budget->dvb_adapter);
- return 0;
-}
-
int ttpci_budget_init (struct budget *budget,
struct saa7146_dev* dev,
struct saa7146_pci_extension_data *info)
@@ -313,15 +292,11 @@ int ttpci_budget_init (struct budget *budget,
if (bi->type != BUDGET_FS_ACTIVY)
saa7146_write(dev, GPIO_CTRL, 0x500000); /* GPIO 3 = 1 */
- budget->i2c_adap = (struct i2c_adapter) {
- .client_register = client_register,
- .client_unregister = client_unregister,
#ifdef I2C_ADAP_CLASS_TV_DIGITAL
- .class = I2C_ADAP_CLASS_TV_DIGITAL,
+ budget->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL;
#else
- .class = I2C_CLASS_TV_DIGITAL,
+ budget->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
#endif
- };
strlcpy(budget->i2c_adap.name, budget->card->name, sizeof(budget->i2c_adap.name));
diff --git a/linux/drivers/media/dvb/ttpci/budget-patch.c b/linux/drivers/media/dvb/ttpci/budget-patch.c
index 6cfe90960..f57fc3b90 100644
--- a/linux/drivers/media/dvb/ttpci/budget-patch.c
+++ b/linux/drivers/media/dvb/ttpci/budget-patch.c
@@ -33,6 +33,9 @@
#include "av7110.h"
#include "av7110_hw.h"
#include "budget.h"
+#include "stv0299.h"
+#include "ves1x93.h"
+#include "tda8083.h"
#define budget_patch budget
@@ -118,45 +121,259 @@ static int av7110_send_diseqc_msg(struct budget_patch *budget, int len, u8 *msg,
return 0;
}
-int budget_patch_diseqc_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
+
+static int budget_patch_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
{
- struct budget_patch *budget = fe->before_after_data;
+ struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
- dprintk(2, "budget: %p\n", budget);
+ switch (tone) {
+ case SEC_TONE_ON:
+ av7110_set22k (budget, 1);
+ break;
- switch (cmd) {
- case FE_SET_TONE:
- switch ((fe_sec_tone_mode_t) arg) {
- case SEC_TONE_ON:
- av7110_set22k (budget, 1);
- break;
- case SEC_TONE_OFF:
- av7110_set22k (budget, 0);
- break;
- default:
- return -EINVAL;
- }
- break;
-
- case FE_DISEQC_SEND_MASTER_CMD:
- {
- struct dvb_diseqc_master_cmd *cmd = arg;
+ case SEC_TONE_OFF:
+ av7110_set22k (budget, 0);
+ break;
- av7110_send_diseqc_msg (budget, cmd->msg_len, cmd->msg, 0);
- break;
- }
+ default:
+ return -EINVAL;
+ }
- case FE_DISEQC_SEND_BURST:
- av7110_send_diseqc_msg (budget, 0, NULL, (int) (long) arg);
- break;
+ return 0;
+}
- default:
- return -EOPNOTSUPP;
- }
+static int budget_patch_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
+{
+ struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
- return 0;
+ av7110_send_diseqc_msg (budget, cmd->msg_len, cmd->msg, 0);
+
+ return 0;
+}
+
+static int budget_patch_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
+{
+ struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
+
+ av7110_send_diseqc_msg (budget, 0, NULL, minicmd);
+
+ return 0;
+}
+
+static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
+ u8 pwr = 0;
+ u8 buf[4];
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+ u32 div = (params->frequency + 479500) / 125;
+
+ if (params->frequency > 2000000) pwr = 3;
+ else if (params->frequency > 1800000) pwr = 2;
+ else if (params->frequency > 1600000) pwr = 1;
+ else if (params->frequency > 1200000) pwr = 0;
+ else if (params->frequency >= 1100000) pwr = 1;
+ else pwr = 2;
+
+ buf[0] = (div >> 8) & 0x7f;
+ buf[1] = div & 0xff;
+ buf[2] = ((div & 0x18000) >> 10) | 0x95;
+ buf[3] = (pwr << 6) | 0x30;
+
+ // NOTE: since we're using a prescaler of 2, we set the
+ // divisor frequency to 62.5kHz and divide by 125 above
+
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+ return 0;
+}
+
+static struct ves1x93_config alps_bsrv2_config = {
+ .demod_address = 0x08,
+ .xin = 90100000UL,
+ .invert_pwm = 0,
+ .pll_set = alps_bsrv2_pll_set,
+};
+
+
+
+static u8 alps_bsru6_inittab[] = {
+ 0x01, 0x15,
+ 0x02, 0x00,
+ 0x03, 0x00,
+ 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+ 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */
+ 0x06, 0x40, /* DAC not used, set to high impendance mode */
+ 0x07, 0x00, /* DAC LSB */
+ 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */
+ 0x09, 0x00, /* FIFO */
+ 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
+ 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */
+ 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
+ 0x10, 0x3f, // AGC2 0x3d
+ 0x11, 0x84,
+ 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on
+ 0x15, 0xc9, // lock detector threshold
+ 0x16, 0x00,
+ 0x17, 0x00,
+ 0x18, 0x00,
+ 0x19, 0x00,
+ 0x1a, 0x00,
+ 0x1f, 0x50,
+ 0x20, 0x00,
+ 0x21, 0x00,
+ 0x22, 0x00,
+ 0x23, 0x00,
+ 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0
+ 0x29, 0x1e, // 1/2 threshold
+ 0x2a, 0x14, // 2/3 threshold
+ 0x2b, 0x0f, // 3/4 threshold
+ 0x2c, 0x09, // 5/6 threshold
+ 0x2d, 0x05, // 7/8 threshold
+ 0x2e, 0x01,
+ 0x31, 0x1f, // test all FECs
+ 0x32, 0x19, // viterbi and synchro search
+ 0x33, 0xfc, // rs control
+ 0x34, 0x93, // error control
+ 0x0f, 0x52,
+ 0xff, 0xff
+};
+
+static int alps_bsru6_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
+{
+ u8 aclk = 0;
+ u8 bclk = 0;
+
+ if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
+ else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
+ else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
+ else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
+ else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
+ else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
+
+ stv0299_writereg (fe, 0x13, aclk);
+ stv0299_writereg (fe, 0x14, bclk);
+ stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff);
+ stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff);
+ stv0299_writereg (fe, 0x21, (ratio ) & 0xf0);
+
+ return 0;
}
+static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
+ u8 data[4];
+ u32 div;
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+ if ((params->frequency < 950000) || (params->frequency > 2150000)) return -EINVAL;
+
+ div = (params->frequency + (125 - 1)) / 125; // round correctly
+ data[0] = (div >> 8) & 0x7f;
+ data[1] = div & 0xff;
+ data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
+ data[3] = 0xC4;
+
+ if (params->frequency > 1530000) data[3] = 0xc0;
+
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+ return 0;
+}
+
+static struct stv0299_config alps_bsru6_config = {
+
+ .demod_address = 0x68,
+ .inittab = alps_bsru6_inittab,
+ .mclk = 88000000UL,
+ .invert = 1,
+ .enhanced_tuning = 0,
+ .skip_reinit = 0,
+ .lock_output = STV0229_LOCKOUTPUT_1,
+ .volt13_op0_op1 = STV0299_VOLT13_OP1,
+ .min_delay_ms = 100,
+ .set_symbol_rate = alps_bsru6_set_symbol_rate,
+ .pll_set = alps_bsru6_pll_set,
+};
+
+
+
+static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
+ u32 div;
+ u8 data[4];
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+ div = params->frequency / 125;
+ data[0] = (div >> 8) & 0x7f;
+ data[1] = div & 0xff;
+ data[2] = 0x8e;
+ data[3] = 0x00;
+
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+ return 0;
+}
+
+struct tda8083_config grundig_29504_451_config = {
+ .demod_address = 0x68,
+ .pll_set = grundig_29504_451_pll_set,
+};
+
+
+
+
+
+static void frontend_init(struct budget_patch* budget)
+{
+ switch(budget->dev->pci->subsystem_device) {
+ case 0x0000: // Hauppauge/TT WinTV DVB-S rev1.X
+
+ // try the ALPS BSRV2 first of all
+ budget->dvb_frontend = ves1x93_attach(&alps_bsrv2_config, &budget->i2c_adap);
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd;
+ budget->dvb_frontend->ops->diseqc_send_burst = budget_patch_diseqc_send_burst;
+ budget->dvb_frontend->ops->set_tone = budget_patch_set_tone;
+ break;
+ }
+
+ // try the ALPS BSRU6 now
+ budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd;
+ budget->dvb_frontend->ops->diseqc_send_burst = budget_patch_diseqc_send_burst;
+ budget->dvb_frontend->ops->set_tone = budget_patch_set_tone;
+ break;
+ }
+
+ // Try the grundig 29504-451
+ budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap);
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd;
+ budget->dvb_frontend->ops->diseqc_send_burst = budget_patch_diseqc_send_burst;
+ budget->dvb_frontend->ops->set_tone = budget_patch_set_tone;
+ break;
+ }
+ break;
+ }
+
+ if (budget->dvb_frontend == NULL) {
+ printk("dvb-ttpci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
+ budget->dev->pci->vendor,
+ budget->dev->pci->device,
+ budget->dev->pci->subsystem_vendor,
+ budget->dev->pci->subsystem_device);
+ } else {
+ if (dvb_register_frontend(budget->dvb_adapter, budget->dvb_frontend)) {
+ printk("budget-av: Frontend registration failed!\n");
+ if (budget->dvb_frontend->ops->release)
+ budget->dvb_frontend->ops->release(budget->dvb_frontend);
+ budget->dvb_frontend = NULL;
+ }
+ }
+}
+
+
static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
{
struct budget_patch *budget;
@@ -216,11 +433,11 @@ static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_exte
// Enable RPS1 (rFC p33)
saa7146_write(dev, MC1, (MASK_13 | MASK_29));
- dvb_add_frontend_ioctls (budget->dvb_adapter,
- budget_patch_diseqc_ioctl, NULL, budget);
-
dev->ext_priv = budget;
+ budget->dvb_adapter->priv = budget;
+ frontend_init(budget);
+
return 0;
}
@@ -229,8 +446,7 @@ static int budget_patch_detach (struct saa7146_dev* dev)
struct budget_patch *budget = (struct budget_patch*) dev->ext_priv;
int err;
- dvb_remove_frontend_ioctls (budget->dvb_adapter,
- budget_patch_diseqc_ioctl, NULL);
+ if (budget->dvb_frontend) dvb_unregister_frontend(budget->dvb_frontend);
err = ttpci_budget_deinit (budget);
diff --git a/linux/drivers/media/dvb/ttpci/budget.c b/linux/drivers/media/dvb/ttpci/budget.c
index a6a3b973f..dc3ae56c7 100644
--- a/linux/drivers/media/dvb/ttpci/budget.c
+++ b/linux/drivers/media/dvb/ttpci/budget.c
@@ -35,6 +35,11 @@
*/
#include "budget.h"
+#include "stv0299.h"
+#include "ves1x93.h"
+#include "ves1820.h"
+#include "l64781.h"
+#include "tda8083.h"
static void Set22K (struct budget *budget, int state)
{
@@ -106,46 +111,6 @@ static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long
}
-int budget_diseqc_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
-{
- struct budget *budget = fe->before_after_data;
-
- dprintk(2, "budget: %p\n", budget);
-
- switch (cmd) {
- case FE_SET_TONE:
- switch ((fe_sec_tone_mode_t) arg) {
- case SEC_TONE_ON:
- Set22K (budget, 1);
- break;
- case SEC_TONE_OFF:
- Set22K (budget, 0);
- break;
- default:
- return -EINVAL;
- };
- break;
-
- case FE_DISEQC_SEND_MASTER_CMD:
- {
- struct dvb_diseqc_master_cmd *cmd = arg;
-
- SendDiSEqCMsg (budget, cmd->msg_len, cmd->msg, 0);
- break;
- }
-
- case FE_DISEQC_SEND_BURST:
- SendDiSEqCMsg (budget, 0, NULL, (unsigned long)arg);
- break;
-
- default:
- return -EOPNOTSUPP;
- };
-
- return 0;
-}
-
-
/*
* Routines for the Fujitsu Siemens Activy budget card
* 22 kHz tone and DiSEqC are handled by the frontend.
@@ -172,22 +137,350 @@ static int SetVoltage_Activy (struct budget *budget, fe_sec_voltage_t voltage)
}
-static int budget_ioctl_activy (struct dvb_frontend *fe, unsigned int cmd, void *arg)
+static int siemens_budget_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
{
- struct budget *budget = fe->before_after_data;
+ struct budget* budget = (struct budget*) fe->dvb->priv;
- dprintk(2, "budget: %p\n", budget);
+ return SetVoltage_Activy (budget, voltage);
+}
- switch (cmd) {
- case FE_SET_VOLTAGE:
- return SetVoltage_Activy (budget, (fe_sec_voltage_t) arg);
- default:
- return -EOPNOTSUPP;
+static int budget_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+ struct budget* budget = (struct budget*) fe->dvb->priv;
+
+ switch (tone) {
+ case SEC_TONE_ON:
+ Set22K (budget, 1);
+ break;
+ case SEC_TONE_OFF:
+ Set22K (budget, 0);
+ break;
}
+ return -EINVAL;
+}
+
+static int budget_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
+{
+ struct budget* budget = (struct budget*) fe->dvb->priv;
+
+ SendDiSEqCMsg (budget, cmd->msg_len, cmd->msg, 0);
+
return 0;
}
+static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
+{
+ struct budget* budget = (struct budget*) fe->dvb->priv;
+
+ SendDiSEqCMsg (budget, 0, NULL, minicmd);
+
+ return 0;
+}
+
+
+static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct budget* budget = (struct budget*) fe->dvb->priv;
+ u8 pwr = 0;
+ u8 buf[4];
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+ u32 div = (params->frequency + 479500) / 125;
+
+ if (params->frequency > 2000000) pwr = 3;
+ else if (params->frequency > 1800000) pwr = 2;
+ else if (params->frequency > 1600000) pwr = 1;
+ else if (params->frequency > 1200000) pwr = 0;
+ else if (params->frequency >= 1100000) pwr = 1;
+ else pwr = 2;
+
+ buf[0] = (div >> 8) & 0x7f;
+ buf[1] = div & 0xff;
+ buf[2] = ((div & 0x18000) >> 10) | 0x95;
+ buf[3] = (pwr << 6) | 0x30;
+
+ // NOTE: since we're using a prescaler of 2, we set the
+ // divisor frequency to 62.5kHz and divide by 125 above
+
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+ return 0;
+}
+
+static struct ves1x93_config alps_bsrv2_config =
+{
+ .demod_address = 0x08,
+ .xin = 90100000UL,
+ .invert_pwm = 0,
+ .pll_set = alps_bsrv2_pll_set,
+};
+
+
+static u8 alps_bsru6_inittab[] = {
+ 0x01, 0x15,
+ 0x02, 0x00,
+ 0x03, 0x00,
+ 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+ 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */
+ 0x06, 0x40, /* DAC not used, set to high impendance mode */
+ 0x07, 0x00, /* DAC LSB */
+ 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */
+ 0x09, 0x00, /* FIFO */
+ 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
+ 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */
+ 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
+ 0x10, 0x3f, // AGC2 0x3d
+ 0x11, 0x84,
+ 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on
+ 0x15, 0xc9, // lock detector threshold
+ 0x16, 0x00,
+ 0x17, 0x00,
+ 0x18, 0x00,
+ 0x19, 0x00,
+ 0x1a, 0x00,
+ 0x1f, 0x50,
+ 0x20, 0x00,
+ 0x21, 0x00,
+ 0x22, 0x00,
+ 0x23, 0x00,
+ 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0
+ 0x29, 0x1e, // 1/2 threshold
+ 0x2a, 0x14, // 2/3 threshold
+ 0x2b, 0x0f, // 3/4 threshold
+ 0x2c, 0x09, // 5/6 threshold
+ 0x2d, 0x05, // 7/8 threshold
+ 0x2e, 0x01,
+ 0x31, 0x1f, // test all FECs
+ 0x32, 0x19, // viterbi and synchro search
+ 0x33, 0xfc, // rs control
+ 0x34, 0x93, // error control
+ 0x0f, 0x52,
+ 0xff, 0xff
+};
+
+static int alps_bsru6_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
+{
+ u8 aclk = 0;
+ u8 bclk = 0;
+
+ if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
+ else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
+ else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
+ else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
+ else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
+ else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
+
+ stv0299_writereg (fe, 0x13, aclk);
+ stv0299_writereg (fe, 0x14, bclk);
+ stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff);
+ stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff);
+ stv0299_writereg (fe, 0x21, (ratio ) & 0xf0);
+
+ return 0;
+}
+
+static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct budget* budget = (struct budget*) fe->dvb->priv;
+ u8 data[4];
+ u32 div;
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+ if ((params->frequency < 950000) || (params->frequency > 2150000)) return -EINVAL;
+
+ div = (params->frequency + (125 - 1)) / 125; // round correctly
+ data[0] = (div >> 8) & 0x7f;
+ data[1] = div & 0xff;
+ data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
+ data[3] = 0xC4;
+
+ if (params->frequency > 1530000) data[3] = 0xc0;
+
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+ return 0;
+}
+
+static struct stv0299_config alps_bsru6_config = {
+
+ .demod_address = 0x68,
+ .inittab = alps_bsru6_inittab,
+ .mclk = 88000000UL,
+ .invert = 1,
+ .enhanced_tuning = 0,
+ .skip_reinit = 0,
+ .lock_output = STV0229_LOCKOUTPUT_1,
+ .volt13_op0_op1 = STV0299_VOLT13_OP1,
+ .min_delay_ms = 100,
+ .set_symbol_rate = alps_bsru6_set_symbol_rate,
+ .pll_set = alps_bsru6_pll_set,
+};
+
+
+
+
+static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct budget* budget = (struct budget*) fe->dvb->priv;
+ u32 div;
+ u8 data[4];
+ struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) };
+
+ div = (params->frequency + 35937500 + 31250) / 62500;
+
+ data[0] = (div >> 8) & 0x7f;
+ data[1] = div & 0xff;
+ data[2] = 0x85 | ((div >> 10) & 0x60);
+ data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81);
+
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+ return 0;
+}
+
+static struct ves1820_config alps_tdbe2_config = {
+ .demod_address = 0x09,
+ .xin = 57840000UL,
+ .invert = 1,
+ .selagc = VES1820_SELAGC_SIGNAMPERR,
+ .pll_set = alps_tdbe2_pll_set,
+};
+
+
+
+static int grundig_29504_401_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct budget* budget = (struct budget*) fe->dvb->priv;
+ u32 div;
+ u8 cfg, cpump, band_select;
+ u8 data[4];
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+ div = (36125000 + params->frequency) / 166666;
+
+ cfg = 0x88;
+
+ if (params->frequency < 175000000) cpump = 2;
+ else if (params->frequency < 390000000) cpump = 1;
+ else if (params->frequency < 470000000) cpump = 2;
+ else if (params->frequency < 750000000) cpump = 1;
+ else cpump = 3;
+
+ if (params->frequency < 175000000) band_select = 0x0e;
+ else if (params->frequency < 470000000) band_select = 0x05;
+ else band_select = 0x03;
+
+ data[0] = (div >> 8) & 0x7f;
+ data[1] = div & 0xff;
+ data[2] = ((div >> 10) & 0x60) | cfg;
+ data[3] = (cpump << 6) | band_select;
+
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+ return 0;
+}
+
+static struct l64781_config grundig_29504_401_config = {
+ .demod_address = 0x55,
+ .pll_set = grundig_29504_401_pll_set,
+};
+
+
+
+
+static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct budget* budget = (struct budget*) fe->dvb->priv;
+ u32 div;
+ u8 data[4];
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+ div = params->frequency / 125;
+ data[0] = (div >> 8) & 0x7f;
+ data[1] = div & 0xff;
+ data[2] = 0x8e;
+ data[3] = 0x00;
+
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+ return 0;
+}
+
+static struct tda8083_config grundig_29504_451_config = {
+ .demod_address = 0x68,
+ .pll_set = grundig_29504_451_pll_set,
+};
+
+static u8 read_pwm(struct budget* budget)
+{
+ u8 b = 0xff;
+ u8 pwm;
+ struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 },
+ { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} };
+
+ if ((i2c_transfer(&budget->i2c_adap, msg, 2) != 2) || (pwm == 0xff))
+ pwm = 0x48;
+
+ return pwm;
+}
+
+static void frontend_init(struct budget *budget)
+{
+ switch(budget->dev->pci->subsystem_device) {
+ case 0x1003: // Hauppauge/TT Nova budget (stv0299/ALPS BSRU6(tsa5059) OR ves1893/ALPS BSRV2(sp5659))
+
+ // try the ALPS BSRV2 first of all
+ budget->dvb_frontend = ves1x93_attach(&alps_bsrv2_config, &budget->i2c_adap);
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
+ budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst;
+ budget->dvb_frontend->ops->set_tone = budget_set_tone;
+ break;
+ }
+
+ // try the ALPS BSRU6 now
+ budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
+ budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst;
+ budget->dvb_frontend->ops->set_tone = budget_set_tone;
+ break;
+ }
+ break;
+
+ case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659))
+
+ budget->dvb_frontend = ves1820_attach(&alps_tdbe2_config, &budget->i2c_adap, read_pwm(budget));
+ if (budget->dvb_frontend) break;
+ break;
+
+ case 0x1005: // Hauppauge/TT Nova-T budget (L64781/Grundig 29504-401(tsa5060))
+
+ budget->dvb_frontend = l64781_attach(&grundig_29504_401_config, &budget->i2c_adap);
+ if (budget->dvb_frontend) break;
+ break;
+
+ case 0x4f61: // Fujitsu Siemens Activy Budget-S PCI (tda8083/Grundig 29504-451(tsa5522))
+
+ // grundig 29504-451
+ budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap);
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops->set_voltage = siemens_budget_set_voltage;
+ break;
+ }
+ break;
+ }
+
+ if (budget->dvb_frontend == NULL) {
+ printk("budget: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
+ budget->dev->pci->vendor,
+ budget->dev->pci->device,
+ budget->dev->pci->subsystem_vendor,
+ budget->dev->pci->subsystem_device);
+ } else {
+ if (dvb_register_frontend(budget->dvb_adapter, budget->dvb_frontend)) {
+ printk("budget: Frontend registration failed!\n");
+ if (budget->dvb_frontend->ops->release)
+ budget->dvb_frontend->ops->release(budget->dvb_frontend);
+ budget->dvb_frontend = NULL;
+ }
+ }
+}
static int budget_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
{
@@ -209,12 +502,8 @@ static int budget_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_
return err;
}
- if (budget->card->type == BUDGET_FS_ACTIVY)
- dvb_add_frontend_ioctls (budget->dvb_adapter,
- budget_ioctl_activy, NULL, budget);
- else
- dvb_add_frontend_ioctls (budget->dvb_adapter,
- budget_diseqc_ioctl, NULL, budget);
+ budget->dvb_adapter->priv = budget;
+ frontend_init(budget);
return 0;
}
@@ -225,12 +514,7 @@ static int budget_detach (struct saa7146_dev* dev)
struct budget *budget = (struct budget*) dev->ext_priv;
int err;
- if (budget->card->type == BUDGET_FS_ACTIVY)
- dvb_remove_frontend_ioctls (budget->dvb_adapter,
- budget_ioctl_activy, NULL);
- else
- dvb_remove_frontend_ioctls (budget->dvb_adapter,
- budget_diseqc_ioctl, NULL);
+ if (budget->dvb_frontend) dvb_unregister_frontend(budget->dvb_frontend);
err = ttpci_budget_deinit (budget);
@@ -247,18 +531,14 @@ static struct saa7146_extension budget_extension;
MAKE_BUDGET_INFO(ttbs, "TT-Budget/WinTV-NOVA-S PCI", BUDGET_TT);
MAKE_BUDGET_INFO(ttbc, "TT-Budget/WinTV-NOVA-C PCI", BUDGET_TT);
MAKE_BUDGET_INFO(ttbt, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
-MAKE_BUDGET_INFO(satel, "SATELCO Multimedia PCI", BUDGET_TT_HW_DISEQC);
+/* MAKE_BUDGET_INFO(satel, "SATELCO Multimedia PCI", BUDGET_TT_HW_DISEQC); UNDEFINED HARDWARE - mail linuxtv.org list */
MAKE_BUDGET_INFO(fsacs, "Fujitsu Siemens Activy Budget-S PCI", BUDGET_FS_ACTIVY);
-/* Uncomment for Budget Patch */
-/*MAKE_BUDGET_INFO(fs_1_3,"Siemens/Technotrend/Hauppauge PCI rev1.3+Budget_Patch", BUDGET_PATCH);*/
static struct pci_device_id pci_tbl[] = {
- /* Uncomment for Budget Patch */
- /*MAKE_EXTENSION_PCI(fs_1_3,0x13c2, 0x0000),*/
MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1003),
MAKE_EXTENSION_PCI(ttbc, 0x13c2, 0x1004),
MAKE_EXTENSION_PCI(ttbt, 0x13c2, 0x1005),
- MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
+/* MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013), UNDEFINED HARDWARE */
MAKE_EXTENSION_PCI(fsacs, 0x1131, 0x4f61),
{
.vendor = 0,
diff --git a/linux/drivers/media/dvb/ttpci/budget.h b/linux/drivers/media/dvb/ttpci/budget.h
index 70bb39af2..3a8095b29 100644
--- a/linux/drivers/media/dvb/ttpci/budget.h
+++ b/linux/drivers/media/dvb/ttpci/budget.h
@@ -62,6 +62,7 @@ struct budget {
spinlock_t feedlock;
struct dvb_adapter *dvb_adapter;
+ struct dvb_frontend *dvb_frontend;
void *priv;
};
@@ -83,7 +84,9 @@ static struct saa7146_pci_extension_data x_var = { \
#define BUDGET_KNC1 2
#define BUDGET_PATCH 3
#define BUDGET_FS_ACTIVY 4
-#define BUDGET_CIN1200 5
+#define BUDGET_CIN1200S 5
+#define BUDGET_CIN1200C 6
+#define BUDGET_CIN1200T 7
#define BUDGET_VIDEO_PORTA 0
#define BUDGET_VIDEO_PORTB 1