budget-patch.c revision fdc53a6dbfea18e621dd23ed5cfb160837d7ce52
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * budget-patch.c: driver for Budget Patch,
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * hardware modification of DVB-S cards enabling full TS
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Written by Emard <emard@softhome.net>
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Original idea by Roberto Deza <rdeza@unav.es>
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Special thanks to Holger Waechtler, Michael Hunold, Marian Durkovic
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and Metzlerbros
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * modify it under the terms of the GNU General Public License
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * as published by the Free Software Foundation; either version 2
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of the License, or (at your option) any later version.
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful,
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * GNU General Public License for more details.
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * along with this program; if not, write to the Free Software
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the project's page is at http://www.linuxtv.org/dvb/
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "av7110.h"
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "av7110_hw.h"
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "budget.h"
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "stv0299.h"
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "ves1x93.h"
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "tda8083.h"
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define budget_patch budget
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct saa7146_extension budget_extension;
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMAKE_BUDGET_INFO(ttbp, "TT-Budget/Patch DVB-S 1.x PCI", BUDGET_PATCH);
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds//MAKE_BUDGET_INFO(satel,"TT-Budget/Patch SATELCO PCI", BUDGET_TT_HW_DISEQC);
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pci_device_id pci_tbl[] = {
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        MAKE_EXTENSION_PCI(ttbp,0x13c2, 0x0000),
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds//        MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        {
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                .vendor    = 0,
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        }
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* those lines are for budget-patch to be tried
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** on a true budget card and observe the
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** behaviour of VSYNC generated by rps1.
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds** this code was shamelessly copy/pasted from budget.c
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void gpio_Set22K (struct budget *budget, int state)
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct saa7146_dev *dev=budget->dev;
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk(2, "budget: %p\n", budget);
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	saa7146_setgpio(dev, 3, (state ? SAA7146_GPIO_OUTHI : SAA7146_GPIO_OUTLO));
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Diseqc functions only for TT Budget card */
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* taken from the Skyvision DVB driver by
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Ralph Metzler <rjkm@metzlerbros.de> */
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void DiseqcSendBit (struct budget *budget, int data)
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct saa7146_dev *dev=budget->dev;
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk(2, "budget: %p\n", budget);
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(data ? 500 : 1000);
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udelay(data ? 1000 : 500);
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void DiseqcSendByte (struct budget *budget, int data)
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, par=1, d;
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk(2, "budget: %p\n", budget);
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i=7; i>=0; i--) {
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		d = (data>>i)&1;
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		par ^= d;
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DiseqcSendBit(budget, d);
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DiseqcSendBit(budget, par);
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long burst)
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct saa7146_dev *dev=budget->dev;
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk(2, "budget: %p\n", budget);
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mdelay(16);
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i=0; i<len; i++)
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DiseqcSendByte(budget, msg[i]);
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mdelay(16);
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (burst!=-1) {
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (burst)
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			DiseqcSendByte(budget, 0xff);
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else {
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			udelay(12500);
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		msleep(20);
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* shamelessly copy/pasted from budget.c
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int budget_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct budget* budget = (struct budget*) fe->dvb->priv;
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (tone) {
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SEC_TONE_ON:
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		gpio_Set22K (budget, 1);
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SEC_TONE_OFF:
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		gpio_Set22K (budget, 0);
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int budget_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct budget* budget = (struct budget*) fe->dvb->priv;
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SendDiSEqCMsg (budget, cmd->msg_len, cmd->msg, 0);
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct budget* budget = (struct budget*) fe->dvb->priv;
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SendDiSEqCMsg (budget, 0, NULL, minicmd);
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int budget_av7110_send_fw_cmd(struct budget_patch *budget, u16* buf, int length)
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        int i;
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        dprintk(2, "budget: %p\n", budget);
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        for (i = 2; i < length; i++)
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        {
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                  ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2*i, 2, (u32) buf[i], 0,0);
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                  msleep(5);
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        }
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        if (length)
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                  ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2, 2, (u32) buf[1], 0,0);
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        else
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                  ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2, 2, 0, 0,0);
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        msleep(5);
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND, 2, (u32) buf[0], 0,0);
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        msleep(5);
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        return 0;
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void av7110_set22k(struct budget_patch *budget, int state)
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        u16 buf[2] = {( COMTYPE_AUDIODAC << 8) | (state ? ON22K : OFF22K), 0};
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        dprintk(2, "budget: %p\n", budget);
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        budget_av7110_send_fw_cmd(budget, buf, 2);
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int av7110_send_diseqc_msg(struct budget_patch *budget, int len, u8 *msg, int burst)
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        int i;
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        u16 buf[18] = { ((COMTYPE_AUDIODAC << 8) | SendDiSEqC),
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        dprintk(2, "budget: %p\n", budget);
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        if (len>10)
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                len=10;
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        buf[1] = len+2;
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        buf[2] = len;
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        if (burst != -1)
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                buf[3]=burst ? 0x01 : 0x00;
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        else
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                buf[3]=0xffff;
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        for (i=0; i<len; i++)
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                buf[i+4]=msg[i];
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        budget_av7110_send_fw_cmd(budget, buf, 18);
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        return 0;
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int budget_patch_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (tone) {
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SEC_TONE_ON:
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		av7110_set22k (budget, 1);
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SEC_TONE_OFF:
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		av7110_set22k (budget, 0);
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int budget_patch_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	av7110_send_diseqc_msg (budget, cmd->msg_len, cmd->msg, 0);
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int budget_patch_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	av7110_send_diseqc_msg (budget, 0, NULL, minicmd);
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 pwr = 0;
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 buf[4];
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 div = (params->frequency + 479500) / 125;
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (params->frequency > 2000000) pwr = 3;
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (params->frequency > 1800000) pwr = 2;
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (params->frequency > 1600000) pwr = 1;
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (params->frequency > 1200000) pwr = 0;
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (params->frequency >= 1100000) pwr = 1;
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else pwr = 2;
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf[0] = (div >> 8) & 0x7f;
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf[1] = div & 0xff;
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf[2] = ((div & 0x18000) >> 10) | 0x95;
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf[3] = (pwr << 6) | 0x30;
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        // NOTE: since we're using a prescaler of 2, we set the
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// divisor frequency to 62.5kHz and divide by 125 above
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct ves1x93_config alps_bsrv2_config = {
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.demod_address = 0x08,
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.xin = 90100000UL,
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.invert_pwm = 0,
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.pll_set = alps_bsrv2_pll_set,
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u8 alps_bsru6_inittab[] = {
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x01, 0x15,
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x02, 0x00,
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x03, 0x00,
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        0x04, 0x7d,   /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x05, 0x35,   /* I2CT = 0, SCLT = 1, SDAT = 1 */
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x06, 0x40,   /* DAC not used, set to high impendance mode */
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x07, 0x00,   /* DAC LSB */
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x08, 0x40,   /* DiSEqC off, LNB power on OP2/LOCK pin on */
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x09, 0x00,   /* FIFO */
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x0c, 0x51,   /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x0d, 0x82,   /* DC offset compensation = ON, beta_agc1 = 2 */
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x0e, 0x23,   /* alpha_tmg = 2, beta_tmg = 3 */
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x10, 0x3f,   // AGC2  0x3d
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x11, 0x84,
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x12, 0xb5,   // Lock detect: -64  Carrier freq detect:on
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x15, 0xc9,   // lock detector threshold
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x16, 0x00,
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x17, 0x00,
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x18, 0x00,
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x19, 0x00,
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x1a, 0x00,
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x1f, 0x50,
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x20, 0x00,
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x21, 0x00,
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x22, 0x00,
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x23, 0x00,
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x28, 0x00,  // out imp: normal  out type: parallel FEC mode:0
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x29, 0x1e,  // 1/2 threshold
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x2a, 0x14,  // 2/3 threshold
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x2b, 0x0f,  // 3/4 threshold
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x2c, 0x09,  // 5/6 threshold
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x2d, 0x05,  // 7/8 threshold
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x2e, 0x01,
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x31, 0x1f,  // test all FECs
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x32, 0x19,  // viterbi and synchro search
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x33, 0xfc,  // rs control
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x34, 0x93,  // error control
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0x0f, 0x52,
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	0xff, 0xff
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int alps_bsru6_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 aclk = 0;
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 bclk = 0;
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	stv0299_writereg (fe, 0x13, aclk);
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	stv0299_writereg (fe, 0x14, bclk);
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff);
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	stv0299_writereg (fe, 0x20, (ratio >>  8) & 0xff);
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	stv0299_writereg (fe, 0x21, (ratio      ) & 0xf0);
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int alps_bsru6_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 data[4];
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 div;
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((params->frequency < 950000) || (params->frequency > 2150000)) return -EINVAL;
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	div = (params->frequency + (125 - 1)) / 125; // round correctly
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data[0] = (div >> 8) & 0x7f;
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data[1] = div & 0xff;
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data[3] = 0xC4;
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (params->frequency > 1530000) data[3] = 0xc0;
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct stv0299_config alps_bsru6_config = {
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.demod_address = 0x68,
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.inittab = alps_bsru6_inittab,
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.mclk = 88000000UL,
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.invert = 1,
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.enhanced_tuning = 0,
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.skip_reinit = 0,
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.lock_output = STV0229_LOCKOUTPUT_1,
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.volt13_op0_op1 = STV0299_VOLT13_OP1,
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.min_delay_ms = 100,
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_symbol_rate = alps_bsru6_set_symbol_rate,
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.pll_set = alps_bsru6_pll_set,
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 div;
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 data[4];
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	div = params->frequency / 125;
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data[0] = (div >> 8) & 0x7f;
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data[1] = div & 0xff;
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data[2] = 0x8e;
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data[3] = 0x00;
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct tda8083_config grundig_29504_451_config = {
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.demod_address = 0x68,
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.pll_set = grundig_29504_451_pll_set,
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void frontend_init(struct budget_patch* budget)
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch(budget->dev->pci->subsystem_device) {
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x0000: // Hauppauge/TT WinTV DVB-S rev1.X
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        case 0x1013: // SATELCO Multimedia PCI
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// try the ALPS BSRV2 first of all
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		budget->dvb_frontend = ves1x93_attach(&alps_bsrv2_config, &budget->i2c_adap);
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (budget->dvb_frontend) {
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd;
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			budget->dvb_frontend->ops->diseqc_send_burst = budget_patch_diseqc_send_burst;
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			budget->dvb_frontend->ops->set_tone = budget_patch_set_tone;
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// try the ALPS BSRU6 now
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (budget->dvb_frontend) {
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst;
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			budget->dvb_frontend->ops->set_tone = budget_set_tone;
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// Try the grundig 29504-451
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap);
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (budget->dvb_frontend) {
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst;
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			budget->dvb_frontend->ops->set_tone = budget_set_tone;
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (budget->dvb_frontend == NULL) {
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("dvb-ttpci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       budget->dev->pci->vendor,
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       budget->dev->pci->device,
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       budget->dev->pci->subsystem_vendor,
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       budget->dev->pci->subsystem_device);
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
456fdc53a6dbfea18e621dd23ed5cfb160837d7ce52Johannes Stezenbach		if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend)) {
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("budget-av: Frontend registration failed!\n");
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (budget->dvb_frontend->ops->release)
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				budget->dvb_frontend->ops->release(budget->dvb_frontend);
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			budget->dvb_frontend = NULL;
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* written by Emard */
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        struct budget_patch *budget;
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        int err;
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int count = 0;
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int detected = 0;
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PATCH_RESET 0
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RPS_IRQ 0
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define HPS_SETUP 0
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if PATCH_RESET
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        saa7146_write(dev, MC1, MASK_31);
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        msleep(40);
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if HPS_SETUP
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        // initialize registers. Better to have it like this
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        // than leaving something unconfigured
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	saa7146_write(dev, DD1_STREAM_B, 0);
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// port B VSYNC at rising edge
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	saa7146_write(dev, DD1_INIT, 0x00000200);  // have this in budget-core too!
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	saa7146_write(dev, BRS_CTRL, 0x00000000);  // VBI
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// debi config
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// saa7146_write(dev, DEBI_CONFIG, MASK_30|MASK_28|MASK_18);
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        // zero all HPS registers
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        saa7146_write(dev, HPS_H_PRESCALE, 0);                  // r68
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        saa7146_write(dev, HPS_H_SCALE, 0);                     // r6c
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        saa7146_write(dev, BCS_CTRL, 0);                        // r70
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        saa7146_write(dev, HPS_V_SCALE, 0);                     // r60
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        saa7146_write(dev, HPS_V_GAIN, 0);                      // r64
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        saa7146_write(dev, CHROMA_KEY_RANGE, 0);                // r74
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        saa7146_write(dev, CLIP_FORMAT_CTRL, 0);                // r78
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        // Set HPS prescaler for port B input
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        saa7146_write(dev, HPS_CTRL, (1<<30) | (0<<29) | (1<<28) | (0<<12) );
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        saa7146_write(dev, MC2,
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds          0 * (MASK_08 | MASK_24)  |   // BRS control
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds          0 * (MASK_09 | MASK_25)  |   // a
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds          0 * (MASK_10 | MASK_26)  |   // b
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds          1 * (MASK_06 | MASK_22)  |   // HPS_CTRL1
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds          1 * (MASK_05 | MASK_21)  |   // HPS_CTRL2
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds          0 * (MASK_01 | MASK_15)      // DEBI
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds           );
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// Disable RPS1 and RPS0
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        saa7146_write(dev, MC1, ( MASK_29 | MASK_28));
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        // RPS1 timeout disable
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        saa7146_write(dev, RPS_TOV1, 0);
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// code for autodetection
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// will wait for VBI_B event (vertical blank at port B)
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// and will reset GPIO3 after VBI_B is detected.
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// (GPIO3 should be raised high by CPU to
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// test if GPIO3 will generate vertical blank signal
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// in budget patch GPIO3 is connected to VSYNC_B
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	count = 0;
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	WRITE_RPS1(cpu_to_le32(CMD_UPLOAD |
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  MASK_10 | MASK_09 | MASK_08 | MASK_06 | MASK_05 | MASK_04 | MASK_03 | MASK_02 ));
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        WRITE_RPS1(cpu_to_le32(CMD_PAUSE | EVT_VBI_B));
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)));
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        WRITE_RPS1(cpu_to_le32(GPIO3_MSK));
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTLO<<24));
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if RPS_IRQ
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        // issue RPS1 interrupt to increment counter
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        // at least a NOP is neede between two interrupts
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        WRITE_RPS1(cpu_to_le32(CMD_NOP));
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        // interrupt again
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        WRITE_RPS1(cpu_to_le32(CMD_STOP));
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if RPS_IRQ
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        // set event counter 1 source as RPS1 interrupt (0x03)          (rE4 p53)
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        // use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        // use 0x15 to track VPE  interrupts - increase by 1 every vpeirq() is called
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        saa7146_write(dev, EC1SSR, (0x03<<2) | 3 );
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        // set event counter 1 treshold to maximum allowed value        (rEC p55)
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        saa7146_write(dev, ECT1R,  0x3fff );
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        // Fix VSYNC level
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        // Set RPS1 Address register to point to RPS code               (r108 p42)
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        // Enable RPS1,                                                 (rFC p33)
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        saa7146_write(dev, MC1, (MASK_13 | MASK_29 ));
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        mdelay(50);
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mdelay(150);
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if( (saa7146_read(dev, GPIO_CTRL) & 0x10000000) == 0)
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		detected = 1;
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if RPS_IRQ
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        printk("Event Counter 1 0x%04x\n", saa7146_read(dev, EC1R) & 0x3fff );
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// Disable RPS1
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        saa7146_write(dev, MC1, ( MASK_29 ));
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(detected == 0)
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                printk("budget-patch not detected or saa7146 in non-default state.\n"
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                       "try enabling ressetting of 7146 with MASK_31 in MC1 register\n");
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                printk("BUDGET-PATCH DETECTED.\n");
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*      OLD (Original design by Roberto Deza):
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      This code will setup the SAA7146_RPS1 to generate a square
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      wave on GPIO3, changing when a field (TS_HEIGHT/2 "lines" of
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      TS_WIDTH packets) has been acquired on SAA7146_D1B video port;
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      then, this GPIO3 output which is connected to the D1B_VSYNC
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      input, will trigger the acquisition of the alternate field
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      and so on.
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      Currently, the TT_budget / WinTV_Nova cards have two ICs
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      (74HCT4040, LVC74) for the generation of this VSYNC signal,
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      which seems that can be done perfectly without this :-)).
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*      New design (By Emard)
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      this rps1 code will copy internal HS event to GPIO3 pin.
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      GPIO3 is in budget-patch hardware connectd to port B VSYNC
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      HS is an internal event of 7146, accessible with RPS
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      and temporarily raised high every n lines
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      (n in defined in the RPS_THRESH1 counter threshold)
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      I think HS is raised high on the beginning of the n-th line
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      and remains high until this n-th line that triggered
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      it is completely received. When the receiption of n-th line
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      ends, HS is lowered.
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      To transmit data over DMA, 7146 needs changing state at
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      port B VSYNC pin. Any changing of port B VSYNC will
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      cause some DMA data transfer, with more or less packets loss.
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      It depends on the phase and frequency of VSYNC and
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      the way of 7146 is instructed to trigger on port B (defined
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      in DD1_INIT register, 3rd nibble from the right valid
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      numbers are 0-7, see datasheet)
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      The correct triggering can minimize packet loss,
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      dvbtraffic should give this stable bandwidths:
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**        22k transponder = 33814 kbit/s
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      27.5k transponder = 38045 kbit/s
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      by experiment it is found that the best results
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      (stable bandwidths and almost no packet loss)
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      are obtained using DD1_INIT triggering number 2
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      (Va at rising edge of VS Fa = HS x VS-failing forced toggle)
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      and a VSYNC phase that occurs in the middle of DMA transfer
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      (about byte 188*512=96256 in the DMA window).
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      Phase of HS is still not clear to me how to control,
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      It just happens to be so. It can be seen if one enables
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      RPS_IRQ and print Event Counter 1 in vpeirq(). Every
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      time RPS_INTERRUPT is called, the Event Counter 1 will
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      increment. That's how the 7146 is programmed to do event
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      counting in this budget-patch.c
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      I *think* HPS setting has something to do with the phase
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      of HS but I cant be 100% sure in that.
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      hardware debug note: a working budget card (including budget patch)
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      with vpeirq() interrupt setup in mode "0x90" (every 64K) will
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      generate 3 interrupts per 25-Hz DMA frame of 2*188*512 bytes
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      and that means 3*25=75 Hz of interrupt freqency, as seen by
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      watch cat /proc/interrupts
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      If this frequency is 3x lower (and data received in the DMA
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      buffer don't start with 0x47, but in the middle of packets,
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      whose lengths appear to be like 188 292 188 104 etc.
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      this means VSYNC line is not connected in the hardware.
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      (check soldering pcb and pins)
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      The same behaviour of missing VSYNC can be duplicated on budget
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds**      cards, by seting DD1_INIT trigger mode 7 in 3rd nibble.
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	// Setup RPS1 "program" (p35)
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        count = 0;
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        // Wait Source Line Counter Threshold                           (p36)
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        WRITE_RPS1(cpu_to_le32(CMD_PAUSE | EVT_HS));
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        // Set GPIO3=1                                                  (p42)
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)));
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        WRITE_RPS1(cpu_to_le32(GPIO3_MSK));
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTHI<<24));
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if RPS_IRQ
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        // issue RPS1 interrupt
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        // Wait reset Source Line Counter Threshold                     (p36)
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        WRITE_RPS1(cpu_to_le32(CMD_PAUSE | RPS_INV | EVT_HS));
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        // Set GPIO3=0                                                  (p42)
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2)));
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        WRITE_RPS1(cpu_to_le32(GPIO3_MSK));
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTLO<<24));
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if RPS_IRQ
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        // issue RPS1 interrupt
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT));
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        // Jump to begin of RPS program                                 (p37)
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        WRITE_RPS1(cpu_to_le32(CMD_JUMP));
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        WRITE_RPS1(cpu_to_le32(dev->d_rps1.dma_handle));
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        // Fix VSYNC level
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        // Set RPS1 Address register to point to RPS code               (r108 p42)
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        // Set Source Line Counter Threshold, using BRS                 (rCC p43)
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        // It generates HS event every TS_HEIGHT lines
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        // this is related to TS_WIDTH set in register
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        // NUM_LINE_BYTE3 in budget-core.c. If NUM_LINE_BYTE
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        // low 16 bits are set to TS_WIDTH bytes (TS_WIDTH=2*188
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        //,then RPS_THRESH1
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        // should be set to trigger every TS_HEIGHT (512) lines.
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        //
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        saa7146_write(dev, RPS_THRESH1, (TS_HEIGHT*1) | MASK_12 );
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        // saa7146_write(dev, RPS_THRESH0, ((TS_HEIGHT/2)<<16) |MASK_28| (TS_HEIGHT/2) |MASK_12 );
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        // Enable RPS1                                                  (rFC p33)
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        saa7146_write(dev, MC1, (MASK_13 | MASK_29));
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        if (!(budget = kmalloc (sizeof(struct budget_patch), GFP_KERNEL)))
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                return -ENOMEM;
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        dprintk(2, "budget: %p\n", budget);
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        if ((err = ttpci_budget_init (budget, dev, info, THIS_MODULE))) {
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                kfree (budget);
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                return err;
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        }
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        dev->ext_priv = budget;
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
705fdc53a6dbfea18e621dd23ed5cfb160837d7ce52Johannes Stezenbach	budget->dvb_adapter.priv = budget;
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	frontend_init(budget);
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        return 0;
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int budget_patch_detach (struct saa7146_dev* dev)
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        struct budget_patch *budget = (struct budget_patch*) dev->ext_priv;
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        int err;
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (budget->dvb_frontend) dvb_unregister_frontend(budget->dvb_frontend);
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        err = ttpci_budget_deinit (budget);
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        kfree (budget);
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        return err;
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init budget_patch_init(void)
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return saa7146_register_extension(&budget_extension);
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit budget_patch_exit(void)
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        saa7146_unregister_extension(&budget_extension);
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct saa7146_extension budget_extension = {
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        .name           = "budget_patch dvb\0",
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        .flags          = 0,
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        .module         = THIS_MODULE,
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        .pci_tbl        = pci_tbl,
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        .attach         = budget_patch_attach,
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        .detach         = budget_patch_detach,
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        .irq_mask       = MASK_10,
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        .irq_func       = ttpci_budget_irq10_handler,
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(budget_patch_init);
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(budget_patch_exit);
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Emard, Roberto Deza, Holger Waechtler, Michael Hunold, others");
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Driver for full TS modified DVB-S SAA7146+AV7110 "
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                   "based so-called Budget Patch cards");
755