18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * budget-patch.c: driver for Budget Patch,
48c2ecf20Sopenharmony_ci * hardware modification of DVB-S cards enabling full TS
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Written by Emard <emard@softhome.net>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Original idea by Roberto Deza <rdeza@unav.es>
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * Special thanks to Holger Waechtler, Michael Hunold, Marian Durkovic
118c2ecf20Sopenharmony_ci * and Metzlerbros
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci * the project's page is at https://linuxtv.org
148c2ecf20Sopenharmony_ci */
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include "av7110.h"
178c2ecf20Sopenharmony_ci#include "av7110_hw.h"
188c2ecf20Sopenharmony_ci#include "budget.h"
198c2ecf20Sopenharmony_ci#include "stv0299.h"
208c2ecf20Sopenharmony_ci#include "ves1x93.h"
218c2ecf20Sopenharmony_ci#include "tda8083.h"
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#include "bsru6.h"
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ciDVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#define budget_patch budget
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic struct saa7146_extension budget_extension;
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ciMAKE_BUDGET_INFO(ttbp, "TT-Budget/Patch DVB-S 1.x PCI", BUDGET_PATCH);
328c2ecf20Sopenharmony_ci//MAKE_BUDGET_INFO(satel,"TT-Budget/Patch SATELCO PCI", BUDGET_TT_HW_DISEQC);
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic const struct pci_device_id pci_tbl[] = {
358c2ecf20Sopenharmony_ci	MAKE_EXTENSION_PCI(ttbp,0x13c2, 0x0000),
368c2ecf20Sopenharmony_ci//        MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
378c2ecf20Sopenharmony_ci	{
388c2ecf20Sopenharmony_ci		.vendor    = 0,
398c2ecf20Sopenharmony_ci	}
408c2ecf20Sopenharmony_ci};
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci/* those lines are for budget-patch to be tried
438c2ecf20Sopenharmony_ci** on a true budget card and observe the
448c2ecf20Sopenharmony_ci** behaviour of VSYNC generated by rps1.
458c2ecf20Sopenharmony_ci** this code was shamelessly copy/pasted from budget.c
468c2ecf20Sopenharmony_ci*/
478c2ecf20Sopenharmony_cistatic void gpio_Set22K (struct budget *budget, int state)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	struct saa7146_dev *dev=budget->dev;
508c2ecf20Sopenharmony_ci	dprintk(2, "budget: %p\n", budget);
518c2ecf20Sopenharmony_ci	saa7146_setgpio(dev, 3, (state ? SAA7146_GPIO_OUTHI : SAA7146_GPIO_OUTLO));
528c2ecf20Sopenharmony_ci}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci/* Diseqc functions only for TT Budget card */
558c2ecf20Sopenharmony_ci/* taken from the Skyvision DVB driver by
568c2ecf20Sopenharmony_ci   Ralph Metzler <rjkm@metzlerbros.de> */
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistatic void DiseqcSendBit (struct budget *budget, int data)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci	struct saa7146_dev *dev=budget->dev;
618c2ecf20Sopenharmony_ci	dprintk(2, "budget: %p\n", budget);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
648c2ecf20Sopenharmony_ci	udelay(data ? 500 : 1000);
658c2ecf20Sopenharmony_ci	saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
668c2ecf20Sopenharmony_ci	udelay(data ? 1000 : 500);
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic void DiseqcSendByte (struct budget *budget, int data)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	int i, par=1, d;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	dprintk(2, "budget: %p\n", budget);
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	for (i=7; i>=0; i--) {
768c2ecf20Sopenharmony_ci		d = (data>>i)&1;
778c2ecf20Sopenharmony_ci		par ^= d;
788c2ecf20Sopenharmony_ci		DiseqcSendBit(budget, d);
798c2ecf20Sopenharmony_ci	}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	DiseqcSendBit(budget, par);
828c2ecf20Sopenharmony_ci}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_cistatic int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long burst)
858c2ecf20Sopenharmony_ci{
868c2ecf20Sopenharmony_ci	struct saa7146_dev *dev=budget->dev;
878c2ecf20Sopenharmony_ci	int i;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	dprintk(2, "budget: %p\n", budget);
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
928c2ecf20Sopenharmony_ci	mdelay(16);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	for (i=0; i<len; i++)
958c2ecf20Sopenharmony_ci		DiseqcSendByte(budget, msg[i]);
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	mdelay(16);
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	if (burst!=-1) {
1008c2ecf20Sopenharmony_ci		if (burst)
1018c2ecf20Sopenharmony_ci			DiseqcSendByte(budget, 0xff);
1028c2ecf20Sopenharmony_ci		else {
1038c2ecf20Sopenharmony_ci			saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
1048c2ecf20Sopenharmony_ci			mdelay(12);
1058c2ecf20Sopenharmony_ci			udelay(500);
1068c2ecf20Sopenharmony_ci			saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
1078c2ecf20Sopenharmony_ci		}
1088c2ecf20Sopenharmony_ci		msleep(20);
1098c2ecf20Sopenharmony_ci	}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	return 0;
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci/* shamelessly copy/pasted from budget.c */
1158c2ecf20Sopenharmony_cistatic int budget_set_tone(struct dvb_frontend *fe,
1168c2ecf20Sopenharmony_ci			   enum fe_sec_tone_mode tone)
1178c2ecf20Sopenharmony_ci{
1188c2ecf20Sopenharmony_ci	struct budget* budget = (struct budget*) fe->dvb->priv;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	switch (tone) {
1218c2ecf20Sopenharmony_ci	case SEC_TONE_ON:
1228c2ecf20Sopenharmony_ci		gpio_Set22K (budget, 1);
1238c2ecf20Sopenharmony_ci		break;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	case SEC_TONE_OFF:
1268c2ecf20Sopenharmony_ci		gpio_Set22K (budget, 0);
1278c2ecf20Sopenharmony_ci		break;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	default:
1308c2ecf20Sopenharmony_ci		return -EINVAL;
1318c2ecf20Sopenharmony_ci	}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	return 0;
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_cistatic int budget_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
1378c2ecf20Sopenharmony_ci{
1388c2ecf20Sopenharmony_ci	struct budget* budget = (struct budget*) fe->dvb->priv;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	SendDiSEqCMsg (budget, cmd->msg_len, cmd->msg, 0);
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	return 0;
1438c2ecf20Sopenharmony_ci}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_cistatic int budget_diseqc_send_burst(struct dvb_frontend *fe,
1468c2ecf20Sopenharmony_ci				    enum fe_sec_mini_cmd minicmd)
1478c2ecf20Sopenharmony_ci{
1488c2ecf20Sopenharmony_ci	struct budget* budget = (struct budget*) fe->dvb->priv;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	SendDiSEqCMsg (budget, 0, NULL, minicmd);
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	return 0;
1538c2ecf20Sopenharmony_ci}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_cistatic int budget_av7110_send_fw_cmd(struct budget_patch *budget, u16* buf, int length)
1568c2ecf20Sopenharmony_ci{
1578c2ecf20Sopenharmony_ci	int i;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	dprintk(2, "budget: %p\n", budget);
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	for (i = 2; i < length; i++)
1628c2ecf20Sopenharmony_ci	{
1638c2ecf20Sopenharmony_ci		  ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2*i, 2, (u32) buf[i], 0,0);
1648c2ecf20Sopenharmony_ci		  msleep(5);
1658c2ecf20Sopenharmony_ci	}
1668c2ecf20Sopenharmony_ci	if (length)
1678c2ecf20Sopenharmony_ci		  ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2, 2, (u32) buf[1], 0,0);
1688c2ecf20Sopenharmony_ci	else
1698c2ecf20Sopenharmony_ci		  ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2, 2, 0, 0,0);
1708c2ecf20Sopenharmony_ci	msleep(5);
1718c2ecf20Sopenharmony_ci	ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND, 2, (u32) buf[0], 0,0);
1728c2ecf20Sopenharmony_ci	msleep(5);
1738c2ecf20Sopenharmony_ci	return 0;
1748c2ecf20Sopenharmony_ci}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_cistatic void av7110_set22k(struct budget_patch *budget, int state)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	u16 buf[2] = {( COMTYPE_AUDIODAC << 8) | (state ? ON22K : OFF22K), 0};
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	dprintk(2, "budget: %p\n", budget);
1818c2ecf20Sopenharmony_ci	budget_av7110_send_fw_cmd(budget, buf, 2);
1828c2ecf20Sopenharmony_ci}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_cistatic int av7110_send_diseqc_msg(struct budget_patch *budget, int len, u8 *msg, int burst)
1858c2ecf20Sopenharmony_ci{
1868c2ecf20Sopenharmony_ci	int i;
1878c2ecf20Sopenharmony_ci	u16 buf[18] = { ((COMTYPE_AUDIODAC << 8) | SendDiSEqC),
1888c2ecf20Sopenharmony_ci		16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	dprintk(2, "budget: %p\n", budget);
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	if (len>10)
1938c2ecf20Sopenharmony_ci		len=10;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	buf[1] = len+2;
1968c2ecf20Sopenharmony_ci	buf[2] = len;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	if (burst != -1)
1998c2ecf20Sopenharmony_ci		buf[3]=burst ? 0x01 : 0x00;
2008c2ecf20Sopenharmony_ci	else
2018c2ecf20Sopenharmony_ci		buf[3]=0xffff;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	for (i=0; i<len; i++)
2048c2ecf20Sopenharmony_ci		buf[i+4]=msg[i];
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	budget_av7110_send_fw_cmd(budget, buf, 18);
2078c2ecf20Sopenharmony_ci	return 0;
2088c2ecf20Sopenharmony_ci}
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_cistatic int budget_patch_set_tone(struct dvb_frontend *fe,
2118c2ecf20Sopenharmony_ci				 enum fe_sec_tone_mode tone)
2128c2ecf20Sopenharmony_ci{
2138c2ecf20Sopenharmony_ci	struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	switch (tone) {
2168c2ecf20Sopenharmony_ci	case SEC_TONE_ON:
2178c2ecf20Sopenharmony_ci		av7110_set22k (budget, 1);
2188c2ecf20Sopenharmony_ci		break;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	case SEC_TONE_OFF:
2218c2ecf20Sopenharmony_ci		av7110_set22k (budget, 0);
2228c2ecf20Sopenharmony_ci		break;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	default:
2258c2ecf20Sopenharmony_ci		return -EINVAL;
2268c2ecf20Sopenharmony_ci	}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	return 0;
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_cistatic int budget_patch_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
2328c2ecf20Sopenharmony_ci{
2338c2ecf20Sopenharmony_ci	struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	av7110_send_diseqc_msg (budget, cmd->msg_len, cmd->msg, 0);
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	return 0;
2388c2ecf20Sopenharmony_ci}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_cistatic int budget_patch_diseqc_send_burst(struct dvb_frontend *fe,
2418c2ecf20Sopenharmony_ci					  enum fe_sec_mini_cmd minicmd)
2428c2ecf20Sopenharmony_ci{
2438c2ecf20Sopenharmony_ci	struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	av7110_send_diseqc_msg (budget, 0, NULL, minicmd);
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	return 0;
2488c2ecf20Sopenharmony_ci}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_cistatic int alps_bsrv2_tuner_set_params(struct dvb_frontend *fe)
2518c2ecf20Sopenharmony_ci{
2528c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
2538c2ecf20Sopenharmony_ci	struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
2548c2ecf20Sopenharmony_ci	u8 pwr = 0;
2558c2ecf20Sopenharmony_ci	u8 buf[4];
2568c2ecf20Sopenharmony_ci	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
2578c2ecf20Sopenharmony_ci	u32 div = (p->frequency + 479500) / 125;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	if (p->frequency > 2000000)
2608c2ecf20Sopenharmony_ci		pwr = 3;
2618c2ecf20Sopenharmony_ci	else if (p->frequency > 1800000)
2628c2ecf20Sopenharmony_ci		pwr = 2;
2638c2ecf20Sopenharmony_ci	else if (p->frequency > 1600000)
2648c2ecf20Sopenharmony_ci		pwr = 1;
2658c2ecf20Sopenharmony_ci	else if (p->frequency > 1200000)
2668c2ecf20Sopenharmony_ci		pwr = 0;
2678c2ecf20Sopenharmony_ci	else if (p->frequency >= 1100000)
2688c2ecf20Sopenharmony_ci		pwr = 1;
2698c2ecf20Sopenharmony_ci	else pwr = 2;
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	buf[0] = (div >> 8) & 0x7f;
2728c2ecf20Sopenharmony_ci	buf[1] = div & 0xff;
2738c2ecf20Sopenharmony_ci	buf[2] = ((div & 0x18000) >> 10) | 0x95;
2748c2ecf20Sopenharmony_ci	buf[3] = (pwr << 6) | 0x30;
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	// NOTE: since we're using a prescaler of 2, we set the
2778c2ecf20Sopenharmony_ci	// divisor frequency to 62.5kHz and divide by 125 above
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	if (fe->ops.i2c_gate_ctrl)
2808c2ecf20Sopenharmony_ci		fe->ops.i2c_gate_ctrl(fe, 1);
2818c2ecf20Sopenharmony_ci	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1)
2828c2ecf20Sopenharmony_ci		return -EIO;
2838c2ecf20Sopenharmony_ci	return 0;
2848c2ecf20Sopenharmony_ci}
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_cistatic struct ves1x93_config alps_bsrv2_config = {
2878c2ecf20Sopenharmony_ci	.demod_address = 0x08,
2888c2ecf20Sopenharmony_ci	.xin = 90100000UL,
2898c2ecf20Sopenharmony_ci	.invert_pwm = 0,
2908c2ecf20Sopenharmony_ci};
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_cistatic int grundig_29504_451_tuner_set_params(struct dvb_frontend *fe)
2938c2ecf20Sopenharmony_ci{
2948c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
2958c2ecf20Sopenharmony_ci	struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
2968c2ecf20Sopenharmony_ci	u32 div;
2978c2ecf20Sopenharmony_ci	u8 data[4];
2988c2ecf20Sopenharmony_ci	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	div = p->frequency / 125;
3018c2ecf20Sopenharmony_ci	data[0] = (div >> 8) & 0x7f;
3028c2ecf20Sopenharmony_ci	data[1] = div & 0xff;
3038c2ecf20Sopenharmony_ci	data[2] = 0x8e;
3048c2ecf20Sopenharmony_ci	data[3] = 0x00;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	if (fe->ops.i2c_gate_ctrl)
3078c2ecf20Sopenharmony_ci		fe->ops.i2c_gate_ctrl(fe, 1);
3088c2ecf20Sopenharmony_ci	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1)
3098c2ecf20Sopenharmony_ci		return -EIO;
3108c2ecf20Sopenharmony_ci	return 0;
3118c2ecf20Sopenharmony_ci}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_cistatic struct tda8083_config grundig_29504_451_config = {
3148c2ecf20Sopenharmony_ci	.demod_address = 0x68,
3158c2ecf20Sopenharmony_ci};
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_cistatic void frontend_init(struct budget_patch* budget)
3188c2ecf20Sopenharmony_ci{
3198c2ecf20Sopenharmony_ci	switch(budget->dev->pci->subsystem_device) {
3208c2ecf20Sopenharmony_ci	case 0x0000: // Hauppauge/TT WinTV DVB-S rev1.X
3218c2ecf20Sopenharmony_ci	case 0x1013: // SATELCO Multimedia PCI
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci		// try the ALPS BSRV2 first of all
3248c2ecf20Sopenharmony_ci		budget->dvb_frontend = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &budget->i2c_adap);
3258c2ecf20Sopenharmony_ci		if (budget->dvb_frontend) {
3268c2ecf20Sopenharmony_ci			budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
3278c2ecf20Sopenharmony_ci			budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd;
3288c2ecf20Sopenharmony_ci			budget->dvb_frontend->ops.diseqc_send_burst = budget_patch_diseqc_send_burst;
3298c2ecf20Sopenharmony_ci			budget->dvb_frontend->ops.set_tone = budget_patch_set_tone;
3308c2ecf20Sopenharmony_ci			break;
3318c2ecf20Sopenharmony_ci		}
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci		// try the ALPS BSRU6 now
3348c2ecf20Sopenharmony_ci		budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config, &budget->i2c_adap);
3358c2ecf20Sopenharmony_ci		if (budget->dvb_frontend) {
3368c2ecf20Sopenharmony_ci			budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
3378c2ecf20Sopenharmony_ci			budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci			budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
3408c2ecf20Sopenharmony_ci			budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;
3418c2ecf20Sopenharmony_ci			budget->dvb_frontend->ops.set_tone = budget_set_tone;
3428c2ecf20Sopenharmony_ci			break;
3438c2ecf20Sopenharmony_ci		}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci		// Try the grundig 29504-451
3468c2ecf20Sopenharmony_ci		budget->dvb_frontend = dvb_attach(tda8083_attach, &grundig_29504_451_config, &budget->i2c_adap);
3478c2ecf20Sopenharmony_ci		if (budget->dvb_frontend) {
3488c2ecf20Sopenharmony_ci			budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
3498c2ecf20Sopenharmony_ci			budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
3508c2ecf20Sopenharmony_ci			budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;
3518c2ecf20Sopenharmony_ci			budget->dvb_frontend->ops.set_tone = budget_set_tone;
3528c2ecf20Sopenharmony_ci			break;
3538c2ecf20Sopenharmony_ci		}
3548c2ecf20Sopenharmony_ci		break;
3558c2ecf20Sopenharmony_ci	}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	if (budget->dvb_frontend == NULL) {
3588c2ecf20Sopenharmony_ci		printk("dvb-ttpci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
3598c2ecf20Sopenharmony_ci		       budget->dev->pci->vendor,
3608c2ecf20Sopenharmony_ci		       budget->dev->pci->device,
3618c2ecf20Sopenharmony_ci		       budget->dev->pci->subsystem_vendor,
3628c2ecf20Sopenharmony_ci		       budget->dev->pci->subsystem_device);
3638c2ecf20Sopenharmony_ci	} else {
3648c2ecf20Sopenharmony_ci		if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend)) {
3658c2ecf20Sopenharmony_ci			printk("budget-av: Frontend registration failed!\n");
3668c2ecf20Sopenharmony_ci			dvb_frontend_detach(budget->dvb_frontend);
3678c2ecf20Sopenharmony_ci			budget->dvb_frontend = NULL;
3688c2ecf20Sopenharmony_ci		}
3698c2ecf20Sopenharmony_ci	}
3708c2ecf20Sopenharmony_ci}
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci/* written by Emard */
3738c2ecf20Sopenharmony_cistatic int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
3748c2ecf20Sopenharmony_ci{
3758c2ecf20Sopenharmony_ci	struct budget_patch *budget;
3768c2ecf20Sopenharmony_ci	int err;
3778c2ecf20Sopenharmony_ci	int count = 0;
3788c2ecf20Sopenharmony_ci	int detected = 0;
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci#define PATCH_RESET 0
3818c2ecf20Sopenharmony_ci#define RPS_IRQ 0
3828c2ecf20Sopenharmony_ci#define HPS_SETUP 0
3838c2ecf20Sopenharmony_ci#if PATCH_RESET
3848c2ecf20Sopenharmony_ci	saa7146_write(dev, MC1, MASK_31);
3858c2ecf20Sopenharmony_ci	msleep(40);
3868c2ecf20Sopenharmony_ci#endif
3878c2ecf20Sopenharmony_ci#if HPS_SETUP
3888c2ecf20Sopenharmony_ci	// initialize registers. Better to have it like this
3898c2ecf20Sopenharmony_ci	// than leaving something unconfigured
3908c2ecf20Sopenharmony_ci	saa7146_write(dev, DD1_STREAM_B, 0);
3918c2ecf20Sopenharmony_ci	// port B VSYNC at rising edge
3928c2ecf20Sopenharmony_ci	saa7146_write(dev, DD1_INIT, 0x00000200);  // have this in budget-core too!
3938c2ecf20Sopenharmony_ci	saa7146_write(dev, BRS_CTRL, 0x00000000);  // VBI
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	// debi config
3968c2ecf20Sopenharmony_ci	// saa7146_write(dev, DEBI_CONFIG, MASK_30|MASK_28|MASK_18);
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	// zero all HPS registers
3998c2ecf20Sopenharmony_ci	saa7146_write(dev, HPS_H_PRESCALE, 0);                  // r68
4008c2ecf20Sopenharmony_ci	saa7146_write(dev, HPS_H_SCALE, 0);                     // r6c
4018c2ecf20Sopenharmony_ci	saa7146_write(dev, BCS_CTRL, 0);                        // r70
4028c2ecf20Sopenharmony_ci	saa7146_write(dev, HPS_V_SCALE, 0);                     // r60
4038c2ecf20Sopenharmony_ci	saa7146_write(dev, HPS_V_GAIN, 0);                      // r64
4048c2ecf20Sopenharmony_ci	saa7146_write(dev, CHROMA_KEY_RANGE, 0);                // r74
4058c2ecf20Sopenharmony_ci	saa7146_write(dev, CLIP_FORMAT_CTRL, 0);                // r78
4068c2ecf20Sopenharmony_ci	// Set HPS prescaler for port B input
4078c2ecf20Sopenharmony_ci	saa7146_write(dev, HPS_CTRL, (1<<30) | (0<<29) | (1<<28) | (0<<12) );
4088c2ecf20Sopenharmony_ci	saa7146_write(dev, MC2,
4098c2ecf20Sopenharmony_ci	  0 * (MASK_08 | MASK_24)  |   // BRS control
4108c2ecf20Sopenharmony_ci	  0 * (MASK_09 | MASK_25)  |   // a
4118c2ecf20Sopenharmony_ci	  0 * (MASK_10 | MASK_26)  |   // b
4128c2ecf20Sopenharmony_ci	  1 * (MASK_06 | MASK_22)  |   // HPS_CTRL1
4138c2ecf20Sopenharmony_ci	  1 * (MASK_05 | MASK_21)  |   // HPS_CTRL2
4148c2ecf20Sopenharmony_ci	  0 * (MASK_01 | MASK_15)      // DEBI
4158c2ecf20Sopenharmony_ci	   );
4168c2ecf20Sopenharmony_ci#endif
4178c2ecf20Sopenharmony_ci	// Disable RPS1 and RPS0
4188c2ecf20Sopenharmony_ci	saa7146_write(dev, MC1, ( MASK_29 | MASK_28));
4198c2ecf20Sopenharmony_ci	// RPS1 timeout disable
4208c2ecf20Sopenharmony_ci	saa7146_write(dev, RPS_TOV1, 0);
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	// code for autodetection
4238c2ecf20Sopenharmony_ci	// will wait for VBI_B event (vertical blank at port B)
4248c2ecf20Sopenharmony_ci	// and will reset GPIO3 after VBI_B is detected.
4258c2ecf20Sopenharmony_ci	// (GPIO3 should be raised high by CPU to
4268c2ecf20Sopenharmony_ci	// test if GPIO3 will generate vertical blank signal
4278c2ecf20Sopenharmony_ci	// in budget patch GPIO3 is connected to VSYNC_B
4288c2ecf20Sopenharmony_ci	count = 0;
4298c2ecf20Sopenharmony_ci#if 0
4308c2ecf20Sopenharmony_ci	WRITE_RPS1(CMD_UPLOAD |
4318c2ecf20Sopenharmony_ci	  MASK_10 | MASK_09 | MASK_08 | MASK_06 | MASK_05 | MASK_04 | MASK_03 | MASK_02 );
4328c2ecf20Sopenharmony_ci#endif
4338c2ecf20Sopenharmony_ci	WRITE_RPS1(CMD_PAUSE | EVT_VBI_B);
4348c2ecf20Sopenharmony_ci	WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
4358c2ecf20Sopenharmony_ci	WRITE_RPS1(GPIO3_MSK);
4368c2ecf20Sopenharmony_ci	WRITE_RPS1(SAA7146_GPIO_OUTLO<<24);
4378c2ecf20Sopenharmony_ci#if RPS_IRQ
4388c2ecf20Sopenharmony_ci	// issue RPS1 interrupt to increment counter
4398c2ecf20Sopenharmony_ci	WRITE_RPS1(CMD_INTERRUPT);
4408c2ecf20Sopenharmony_ci	// at least a NOP is neede between two interrupts
4418c2ecf20Sopenharmony_ci	WRITE_RPS1(CMD_NOP);
4428c2ecf20Sopenharmony_ci	// interrupt again
4438c2ecf20Sopenharmony_ci	WRITE_RPS1(CMD_INTERRUPT);
4448c2ecf20Sopenharmony_ci#endif
4458c2ecf20Sopenharmony_ci	WRITE_RPS1(CMD_STOP);
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci#if RPS_IRQ
4488c2ecf20Sopenharmony_ci	// set event counter 1 source as RPS1 interrupt (0x03)          (rE4 p53)
4498c2ecf20Sopenharmony_ci	// use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled
4508c2ecf20Sopenharmony_ci	// use 0x15 to track VPE  interrupts - increase by 1 every vpeirq() is called
4518c2ecf20Sopenharmony_ci	saa7146_write(dev, EC1SSR, (0x03<<2) | 3 );
4528c2ecf20Sopenharmony_ci	// set event counter 1 threshold to maximum allowed value        (rEC p55)
4538c2ecf20Sopenharmony_ci	saa7146_write(dev, ECT1R,  0x3fff );
4548c2ecf20Sopenharmony_ci#endif
4558c2ecf20Sopenharmony_ci	// Fix VSYNC level
4568c2ecf20Sopenharmony_ci	saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
4578c2ecf20Sopenharmony_ci	// Set RPS1 Address register to point to RPS code               (r108 p42)
4588c2ecf20Sopenharmony_ci	saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);
4598c2ecf20Sopenharmony_ci	// Enable RPS1,                                                 (rFC p33)
4608c2ecf20Sopenharmony_ci	saa7146_write(dev, MC1, (MASK_13 | MASK_29 ));
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	mdelay(50);
4648c2ecf20Sopenharmony_ci	saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
4658c2ecf20Sopenharmony_ci	mdelay(150);
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	if( (saa7146_read(dev, GPIO_CTRL) & 0x10000000) == 0)
4698c2ecf20Sopenharmony_ci		detected = 1;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci#if RPS_IRQ
4728c2ecf20Sopenharmony_ci	printk("Event Counter 1 0x%04x\n", saa7146_read(dev, EC1R) & 0x3fff );
4738c2ecf20Sopenharmony_ci#endif
4748c2ecf20Sopenharmony_ci	// Disable RPS1
4758c2ecf20Sopenharmony_ci	saa7146_write(dev, MC1, ( MASK_29 ));
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	if(detected == 0)
4788c2ecf20Sopenharmony_ci		printk("budget-patch not detected or saa7146 in non-default state.\n"
4798c2ecf20Sopenharmony_ci		       "try enabling resetting of 7146 with MASK_31 in MC1 register\n");
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	else
4828c2ecf20Sopenharmony_ci		printk("BUDGET-PATCH DETECTED.\n");
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci/*      OLD (Original design by Roberto Deza):
4868c2ecf20Sopenharmony_ci**      This code will setup the SAA7146_RPS1 to generate a square
4878c2ecf20Sopenharmony_ci**      wave on GPIO3, changing when a field (TS_HEIGHT/2 "lines" of
4888c2ecf20Sopenharmony_ci**      TS_WIDTH packets) has been acquired on SAA7146_D1B video port;
4898c2ecf20Sopenharmony_ci**      then, this GPIO3 output which is connected to the D1B_VSYNC
4908c2ecf20Sopenharmony_ci**      input, will trigger the acquisition of the alternate field
4918c2ecf20Sopenharmony_ci**      and so on.
4928c2ecf20Sopenharmony_ci**      Currently, the TT_budget / WinTV_Nova cards have two ICs
4938c2ecf20Sopenharmony_ci**      (74HCT4040, LVC74) for the generation of this VSYNC signal,
4948c2ecf20Sopenharmony_ci**      which seems that can be done perfectly without this :-)).
4958c2ecf20Sopenharmony_ci*/
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci/*      New design (By Emard)
4988c2ecf20Sopenharmony_ci**      this rps1 code will copy internal HS event to GPIO3 pin.
4998c2ecf20Sopenharmony_ci**      GPIO3 is in budget-patch hardware connected to port B VSYNC
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci**      HS is an internal event of 7146, accessible with RPS
5028c2ecf20Sopenharmony_ci**      and temporarily raised high every n lines
5038c2ecf20Sopenharmony_ci**      (n in defined in the RPS_THRESH1 counter threshold)
5048c2ecf20Sopenharmony_ci**      I think HS is raised high on the beginning of the n-th line
5058c2ecf20Sopenharmony_ci**      and remains high until this n-th line that triggered
5068c2ecf20Sopenharmony_ci**      it is completely received. When the reception of n-th line
5078c2ecf20Sopenharmony_ci**      ends, HS is lowered.
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci**      To transmit data over DMA, 7146 needs changing state at
5108c2ecf20Sopenharmony_ci**      port B VSYNC pin. Any changing of port B VSYNC will
5118c2ecf20Sopenharmony_ci**      cause some DMA data transfer, with more or less packets loss.
5128c2ecf20Sopenharmony_ci**      It depends on the phase and frequency of VSYNC and
5138c2ecf20Sopenharmony_ci**      the way of 7146 is instructed to trigger on port B (defined
5148c2ecf20Sopenharmony_ci**      in DD1_INIT register, 3rd nibble from the right valid
5158c2ecf20Sopenharmony_ci**      numbers are 0-7, see datasheet)
5168c2ecf20Sopenharmony_ci**
5178c2ecf20Sopenharmony_ci**      The correct triggering can minimize packet loss,
5188c2ecf20Sopenharmony_ci**      dvbtraffic should give this stable bandwidths:
5198c2ecf20Sopenharmony_ci**        22k transponder = 33814 kbit/s
5208c2ecf20Sopenharmony_ci**      27.5k transponder = 38045 kbit/s
5218c2ecf20Sopenharmony_ci**      by experiment it is found that the best results
5228c2ecf20Sopenharmony_ci**      (stable bandwidths and almost no packet loss)
5238c2ecf20Sopenharmony_ci**      are obtained using DD1_INIT triggering number 2
5248c2ecf20Sopenharmony_ci**      (Va at rising edge of VS Fa = HS x VS-failing forced toggle)
5258c2ecf20Sopenharmony_ci**      and a VSYNC phase that occurs in the middle of DMA transfer
5268c2ecf20Sopenharmony_ci**      (about byte 188*512=96256 in the DMA window).
5278c2ecf20Sopenharmony_ci**
5288c2ecf20Sopenharmony_ci**      Phase of HS is still not clear to me how to control,
5298c2ecf20Sopenharmony_ci**      It just happens to be so. It can be seen if one enables
5308c2ecf20Sopenharmony_ci**      RPS_IRQ and print Event Counter 1 in vpeirq(). Every
5318c2ecf20Sopenharmony_ci**      time RPS_INTERRUPT is called, the Event Counter 1 will
5328c2ecf20Sopenharmony_ci**      increment. That's how the 7146 is programmed to do event
5338c2ecf20Sopenharmony_ci**      counting in this budget-patch.c
5348c2ecf20Sopenharmony_ci**      I *think* HPS setting has something to do with the phase
5358c2ecf20Sopenharmony_ci**      of HS but I can't be 100% sure in that.
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci**      hardware debug note: a working budget card (including budget patch)
5388c2ecf20Sopenharmony_ci**      with vpeirq() interrupt setup in mode "0x90" (every 64K) will
5398c2ecf20Sopenharmony_ci**      generate 3 interrupts per 25-Hz DMA frame of 2*188*512 bytes
5408c2ecf20Sopenharmony_ci**      and that means 3*25=75 Hz of interrupt frequency, as seen by
5418c2ecf20Sopenharmony_ci**      watch cat /proc/interrupts
5428c2ecf20Sopenharmony_ci**
5438c2ecf20Sopenharmony_ci**      If this frequency is 3x lower (and data received in the DMA
5448c2ecf20Sopenharmony_ci**      buffer don't start with 0x47, but in the middle of packets,
5458c2ecf20Sopenharmony_ci**      whose lengths appear to be like 188 292 188 104 etc.
5468c2ecf20Sopenharmony_ci**      this means VSYNC line is not connected in the hardware.
5478c2ecf20Sopenharmony_ci**      (check soldering pcb and pins)
5488c2ecf20Sopenharmony_ci**      The same behaviour of missing VSYNC can be duplicated on budget
5498c2ecf20Sopenharmony_ci**      cards, by setting DD1_INIT trigger mode 7 in 3rd nibble.
5508c2ecf20Sopenharmony_ci*/
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	// Setup RPS1 "program" (p35)
5538c2ecf20Sopenharmony_ci	count = 0;
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	// Wait Source Line Counter Threshold                           (p36)
5578c2ecf20Sopenharmony_ci	WRITE_RPS1(CMD_PAUSE | EVT_HS);
5588c2ecf20Sopenharmony_ci	// Set GPIO3=1                                                  (p42)
5598c2ecf20Sopenharmony_ci	WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
5608c2ecf20Sopenharmony_ci	WRITE_RPS1(GPIO3_MSK);
5618c2ecf20Sopenharmony_ci	WRITE_RPS1(SAA7146_GPIO_OUTHI<<24);
5628c2ecf20Sopenharmony_ci#if RPS_IRQ
5638c2ecf20Sopenharmony_ci	// issue RPS1 interrupt
5648c2ecf20Sopenharmony_ci	WRITE_RPS1(CMD_INTERRUPT);
5658c2ecf20Sopenharmony_ci#endif
5668c2ecf20Sopenharmony_ci	// Wait reset Source Line Counter Threshold                     (p36)
5678c2ecf20Sopenharmony_ci	WRITE_RPS1(CMD_PAUSE | RPS_INV | EVT_HS);
5688c2ecf20Sopenharmony_ci	// Set GPIO3=0                                                  (p42)
5698c2ecf20Sopenharmony_ci	WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
5708c2ecf20Sopenharmony_ci	WRITE_RPS1(GPIO3_MSK);
5718c2ecf20Sopenharmony_ci	WRITE_RPS1(SAA7146_GPIO_OUTLO<<24);
5728c2ecf20Sopenharmony_ci#if RPS_IRQ
5738c2ecf20Sopenharmony_ci	// issue RPS1 interrupt
5748c2ecf20Sopenharmony_ci	WRITE_RPS1(CMD_INTERRUPT);
5758c2ecf20Sopenharmony_ci#endif
5768c2ecf20Sopenharmony_ci	// Jump to begin of RPS program                                 (p37)
5778c2ecf20Sopenharmony_ci	WRITE_RPS1(CMD_JUMP);
5788c2ecf20Sopenharmony_ci	WRITE_RPS1(dev->d_rps1.dma_handle);
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	// Fix VSYNC level
5818c2ecf20Sopenharmony_ci	saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
5828c2ecf20Sopenharmony_ci	// Set RPS1 Address register to point to RPS code               (r108 p42)
5838c2ecf20Sopenharmony_ci	saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	if (!(budget = kmalloc (sizeof(struct budget_patch), GFP_KERNEL)))
5868c2ecf20Sopenharmony_ci		return -ENOMEM;
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	dprintk(2, "budget: %p\n", budget);
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	err = ttpci_budget_init(budget, dev, info, THIS_MODULE, adapter_nr);
5918c2ecf20Sopenharmony_ci	if (err) {
5928c2ecf20Sopenharmony_ci		kfree(budget);
5938c2ecf20Sopenharmony_ci		return err;
5948c2ecf20Sopenharmony_ci	}
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci	// Set Source Line Counter Threshold, using BRS                 (rCC p43)
5978c2ecf20Sopenharmony_ci	// It generates HS event every TS_HEIGHT lines
5988c2ecf20Sopenharmony_ci	// this is related to TS_WIDTH set in register
5998c2ecf20Sopenharmony_ci	// NUM_LINE_BYTE3 in budget-core.c. If NUM_LINE_BYTE
6008c2ecf20Sopenharmony_ci	// low 16 bits are set to TS_WIDTH bytes (TS_WIDTH=2*188
6018c2ecf20Sopenharmony_ci	//,then RPS_THRESH1
6028c2ecf20Sopenharmony_ci	// should be set to trigger every TS_HEIGHT (512) lines.
6038c2ecf20Sopenharmony_ci	//
6048c2ecf20Sopenharmony_ci	saa7146_write(dev, RPS_THRESH1, budget->buffer_height | MASK_12 );
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	// saa7146_write(dev, RPS_THRESH0, ((TS_HEIGHT/2)<<16) |MASK_28| (TS_HEIGHT/2) |MASK_12 );
6078c2ecf20Sopenharmony_ci	// Enable RPS1                                                  (rFC p33)
6088c2ecf20Sopenharmony_ci	saa7146_write(dev, MC1, (MASK_13 | MASK_29));
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	dev->ext_priv = budget;
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci	budget->dvb_adapter.priv = budget;
6148c2ecf20Sopenharmony_ci	frontend_init(budget);
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	ttpci_budget_init_hooks(budget);
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	return 0;
6198c2ecf20Sopenharmony_ci}
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_cistatic int budget_patch_detach (struct saa7146_dev* dev)
6228c2ecf20Sopenharmony_ci{
6238c2ecf20Sopenharmony_ci	struct budget_patch *budget = (struct budget_patch*) dev->ext_priv;
6248c2ecf20Sopenharmony_ci	int err;
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	if (budget->dvb_frontend) {
6278c2ecf20Sopenharmony_ci		dvb_unregister_frontend(budget->dvb_frontend);
6288c2ecf20Sopenharmony_ci		dvb_frontend_detach(budget->dvb_frontend);
6298c2ecf20Sopenharmony_ci	}
6308c2ecf20Sopenharmony_ci	err = ttpci_budget_deinit (budget);
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	kfree (budget);
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	return err;
6358c2ecf20Sopenharmony_ci}
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_cistatic int __init budget_patch_init(void)
6388c2ecf20Sopenharmony_ci{
6398c2ecf20Sopenharmony_ci	return saa7146_register_extension(&budget_extension);
6408c2ecf20Sopenharmony_ci}
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_cistatic void __exit budget_patch_exit(void)
6438c2ecf20Sopenharmony_ci{
6448c2ecf20Sopenharmony_ci	saa7146_unregister_extension(&budget_extension);
6458c2ecf20Sopenharmony_ci}
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_cistatic struct saa7146_extension budget_extension = {
6488c2ecf20Sopenharmony_ci	.name           = "budget_patch dvb",
6498c2ecf20Sopenharmony_ci	.flags          = 0,
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	.module         = THIS_MODULE,
6528c2ecf20Sopenharmony_ci	.pci_tbl        = pci_tbl,
6538c2ecf20Sopenharmony_ci	.attach         = budget_patch_attach,
6548c2ecf20Sopenharmony_ci	.detach         = budget_patch_detach,
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	.irq_mask       = MASK_10,
6578c2ecf20Sopenharmony_ci	.irq_func       = ttpci_budget_irq10_handler,
6588c2ecf20Sopenharmony_ci};
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_cimodule_init(budget_patch_init);
6618c2ecf20Sopenharmony_cimodule_exit(budget_patch_exit);
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
6648c2ecf20Sopenharmony_ciMODULE_AUTHOR("Emard, Roberto Deza, Holger Waechtler, Michael Hunold, others");
6658c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Driver for full TS modified DVB-S SAA7146+AV7110 based so-called Budget Patch cards");
666