Path: blob/master/drivers/media/dvb/ttpci/budget-av.c
15111 views
/*1* budget-av.c: driver for the SAA7146 based Budget DVB cards2* with analog video in3*4* Compiled from various sources by Michael Hunold <[email protected]>5*6* CI interface support (c) 2004 Olivier Gournet <[email protected]> &7* Andrew de Quincey <[email protected]>8*9* Copyright (C) 2002 Ralph Metzler <[email protected]>10*11* Copyright (C) 1999-2002 Ralph Metzler12* & Marcus Metzler for convergence integrated media GmbH13*14* This program is free software; you can redistribute it and/or15* modify it under the terms of the GNU General Public License16* as published by the Free Software Foundation; either version 217* of the License, or (at your option) any later version.18*19*20* This program is distributed in the hope that it will be useful,21* but WITHOUT ANY WARRANTY; without even the implied warranty of22* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the23* GNU General Public License for more details.24*25*26* You should have received a copy of the GNU General Public License27* along with this program; if not, write to the Free Software28* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.29* Or, point your browser to http://www.gnu.org/copyleft/gpl.html30*31*32* the project's page is at http://www.linuxtv.org/33*/3435#include "budget.h"36#include "stv0299.h"37#include "stb0899_drv.h"38#include "stb0899_reg.h"39#include "stb0899_cfg.h"40#include "tda8261.h"41#include "tda8261_cfg.h"42#include "tda1002x.h"43#include "tda1004x.h"44#include "tua6100.h"45#include "dvb-pll.h"46#include <media/saa7146_vv.h>47#include <linux/module.h>48#include <linux/errno.h>49#include <linux/slab.h>50#include <linux/interrupt.h>51#include <linux/input.h>52#include <linux/spinlock.h>5354#include "dvb_ca_en50221.h"5556#define DEBICICAM 0x024200005758#define SLOTSTATUS_NONE 159#define SLOTSTATUS_PRESENT 260#define SLOTSTATUS_RESET 461#define SLOTSTATUS_READY 862#define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY)6364DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);6566struct budget_av {67struct budget budget;68struct video_device *vd;69int cur_input;70int has_saa7113;71struct tasklet_struct ciintf_irq_tasklet;72int slot_status;73struct dvb_ca_en50221 ca;74u8 reinitialise_demod:1;75};7677static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot);787980/* GPIO Connections:81* 0 - Vcc/Reset (Reset is controlled by capacitor). Resets the frontend *AS WELL*!82* 1 - CI memory select 0=>IO memory, 1=>Attribute Memory83* 2 - CI Card Enable (Active Low)84* 3 - CI Card Detect85*/8687/****************************************************************************88* INITIALIZATION89****************************************************************************/9091static u8 i2c_readreg(struct i2c_adapter *i2c, u8 id, u8 reg)92{93u8 mm1[] = { 0x00 };94u8 mm2[] = { 0x00 };95struct i2c_msg msgs[2];9697msgs[0].flags = 0;98msgs[1].flags = I2C_M_RD;99msgs[0].addr = msgs[1].addr = id / 2;100mm1[0] = reg;101msgs[0].len = 1;102msgs[1].len = 1;103msgs[0].buf = mm1;104msgs[1].buf = mm2;105106i2c_transfer(i2c, msgs, 2);107108return mm2[0];109}110111static int i2c_readregs(struct i2c_adapter *i2c, u8 id, u8 reg, u8 * buf, u8 len)112{113u8 mm1[] = { reg };114struct i2c_msg msgs[2] = {115{.addr = id / 2,.flags = 0,.buf = mm1,.len = 1},116{.addr = id / 2,.flags = I2C_M_RD,.buf = buf,.len = len}117};118119if (i2c_transfer(i2c, msgs, 2) != 2)120return -EIO;121122return 0;123}124125static int i2c_writereg(struct i2c_adapter *i2c, u8 id, u8 reg, u8 val)126{127u8 msg[2] = { reg, val };128struct i2c_msg msgs;129130msgs.flags = 0;131msgs.addr = id / 2;132msgs.len = 2;133msgs.buf = msg;134return i2c_transfer(i2c, &msgs, 1);135}136137static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)138{139struct budget_av *budget_av = (struct budget_av *) ca->data;140int result;141142if (slot != 0)143return -EINVAL;144145saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI);146udelay(1);147148result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 1);149if (result == -ETIMEDOUT) {150ciintf_slot_shutdown(ca, slot);151printk(KERN_INFO "budget-av: cam ejected 1\n");152}153return result;154}155156static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)157{158struct budget_av *budget_av = (struct budget_av *) ca->data;159int result;160161if (slot != 0)162return -EINVAL;163164saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI);165udelay(1);166167result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 1);168if (result == -ETIMEDOUT) {169ciintf_slot_shutdown(ca, slot);170printk(KERN_INFO "budget-av: cam ejected 2\n");171}172return result;173}174175static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)176{177struct budget_av *budget_av = (struct budget_av *) ca->data;178int result;179180if (slot != 0)181return -EINVAL;182183saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);184udelay(1);185186result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 3, 1, 0, 0);187if (result == -ETIMEDOUT) {188ciintf_slot_shutdown(ca, slot);189printk(KERN_INFO "budget-av: cam ejected 3\n");190return -ETIMEDOUT;191}192return result;193}194195static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)196{197struct budget_av *budget_av = (struct budget_av *) ca->data;198int result;199200if (slot != 0)201return -EINVAL;202203saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);204udelay(1);205206result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 3, 1, value, 0, 0);207if (result == -ETIMEDOUT) {208ciintf_slot_shutdown(ca, slot);209printk(KERN_INFO "budget-av: cam ejected 5\n");210}211return result;212}213214static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)215{216struct budget_av *budget_av = (struct budget_av *) ca->data;217struct saa7146_dev *saa = budget_av->budget.dev;218219if (slot != 0)220return -EINVAL;221222dprintk(1, "ciintf_slot_reset\n");223budget_av->slot_status = SLOTSTATUS_RESET;224225saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */226227saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI); /* Vcc off */228msleep(2);229saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO); /* Vcc on */230msleep(20); /* 20 ms Vcc settling time */231232saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO); /* enable card */233ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);234msleep(20);235236/* reinitialise the frontend if necessary */237if (budget_av->reinitialise_demod)238dvb_frontend_reinitialise(budget_av->budget.dvb_frontend);239240return 0;241}242243static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)244{245struct budget_av *budget_av = (struct budget_av *) ca->data;246struct saa7146_dev *saa = budget_av->budget.dev;247248if (slot != 0)249return -EINVAL;250251dprintk(1, "ciintf_slot_shutdown\n");252253ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);254budget_av->slot_status = SLOTSTATUS_NONE;255256return 0;257}258259static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)260{261struct budget_av *budget_av = (struct budget_av *) ca->data;262struct saa7146_dev *saa = budget_av->budget.dev;263264if (slot != 0)265return -EINVAL;266267dprintk(1, "ciintf_slot_ts_enable: %d\n", budget_av->slot_status);268269ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);270271return 0;272}273274static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)275{276struct budget_av *budget_av = (struct budget_av *) ca->data;277struct saa7146_dev *saa = budget_av->budget.dev;278int result;279280if (slot != 0)281return -EINVAL;282283/* test the card detect line - needs to be done carefully284* since it never goes high for some CAMs on this interface (e.g. topuptv) */285if (budget_av->slot_status == SLOTSTATUS_NONE) {286saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);287udelay(1);288if (saa7146_read(saa, PSR) & MASK_06) {289if (budget_av->slot_status == SLOTSTATUS_NONE) {290budget_av->slot_status = SLOTSTATUS_PRESENT;291printk(KERN_INFO "budget-av: cam inserted A\n");292}293}294saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);295}296297/* We also try and read from IO memory to work round the above detection bug. If298* there is no CAM, we will get a timeout. Only done if there is no cam299* present, since this test actually breaks some cams :(300*301* if the CI interface is not open, we also do the above test since we302* don't care if the cam has problems - we'll be resetting it on open() anyway */303if ((budget_av->slot_status == SLOTSTATUS_NONE) || (!open)) {304saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);305result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1);306if ((result >= 0) && (budget_av->slot_status == SLOTSTATUS_NONE)) {307budget_av->slot_status = SLOTSTATUS_PRESENT;308printk(KERN_INFO "budget-av: cam inserted B\n");309} else if (result < 0) {310if (budget_av->slot_status != SLOTSTATUS_NONE) {311ciintf_slot_shutdown(ca, slot);312printk(KERN_INFO "budget-av: cam ejected 5\n");313return 0;314}315}316}317318/* read from attribute memory in reset/ready state to know when the CAM is ready */319if (budget_av->slot_status == SLOTSTATUS_RESET) {320result = ciintf_read_attribute_mem(ca, slot, 0);321if (result == 0x1d) {322budget_av->slot_status = SLOTSTATUS_READY;323}324}325326/* work out correct return code */327if (budget_av->slot_status != SLOTSTATUS_NONE) {328if (budget_av->slot_status & SLOTSTATUS_READY) {329return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;330}331return DVB_CA_EN50221_POLL_CAM_PRESENT;332}333return 0;334}335336static int ciintf_init(struct budget_av *budget_av)337{338struct saa7146_dev *saa = budget_av->budget.dev;339int result;340341memset(&budget_av->ca, 0, sizeof(struct dvb_ca_en50221));342343saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO);344saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO);345saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO);346saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);347348/* Enable DEBI pins */349saa7146_write(saa, MC1, MASK_27 | MASK_11);350351/* register CI interface */352budget_av->ca.owner = THIS_MODULE;353budget_av->ca.read_attribute_mem = ciintf_read_attribute_mem;354budget_av->ca.write_attribute_mem = ciintf_write_attribute_mem;355budget_av->ca.read_cam_control = ciintf_read_cam_control;356budget_av->ca.write_cam_control = ciintf_write_cam_control;357budget_av->ca.slot_reset = ciintf_slot_reset;358budget_av->ca.slot_shutdown = ciintf_slot_shutdown;359budget_av->ca.slot_ts_enable = ciintf_slot_ts_enable;360budget_av->ca.poll_slot_status = ciintf_poll_slot_status;361budget_av->ca.data = budget_av;362budget_av->budget.ci_present = 1;363budget_av->slot_status = SLOTSTATUS_NONE;364365if ((result = dvb_ca_en50221_init(&budget_av->budget.dvb_adapter,366&budget_av->ca, 0, 1)) != 0) {367printk(KERN_ERR "budget-av: ci initialisation failed.\n");368goto error;369}370371printk(KERN_INFO "budget-av: ci interface initialised.\n");372return 0;373374error:375saa7146_write(saa, MC1, MASK_27);376return result;377}378379static void ciintf_deinit(struct budget_av *budget_av)380{381struct saa7146_dev *saa = budget_av->budget.dev;382383saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);384saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT);385saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT);386saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);387388/* release the CA device */389dvb_ca_en50221_release(&budget_av->ca);390391/* disable DEBI pins */392saa7146_write(saa, MC1, MASK_27);393}394395396static const u8 saa7113_tab[] = {3970x01, 0x08,3980x02, 0xc0,3990x03, 0x33,4000x04, 0x00,4010x05, 0x00,4020x06, 0xeb,4030x07, 0xe0,4040x08, 0x28,4050x09, 0x00,4060x0a, 0x80,4070x0b, 0x47,4080x0c, 0x40,4090x0d, 0x00,4100x0e, 0x01,4110x0f, 0x44,4124130x10, 0x08,4140x11, 0x0c,4150x12, 0x7b,4160x13, 0x00,4170x15, 0x00, 0x16, 0x00, 0x17, 0x00,4184190x57, 0xff,4200x40, 0x82, 0x58, 0x00, 0x59, 0x54, 0x5a, 0x07,4210x5b, 0x83, 0x5e, 0x00,4220xff423};424425static int saa7113_init(struct budget_av *budget_av)426{427struct budget *budget = &budget_av->budget;428struct saa7146_dev *saa = budget->dev;429const u8 *data = saa7113_tab;430431saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI);432msleep(200);433434if (i2c_writereg(&budget->i2c_adap, 0x4a, 0x01, 0x08) != 1) {435dprintk(1, "saa7113 not found on KNC card\n");436return -ENODEV;437}438439dprintk(1, "saa7113 detected and initializing\n");440441while (*data != 0xff) {442i2c_writereg(&budget->i2c_adap, 0x4a, *data, *(data + 1));443data += 2;444}445446dprintk(1, "saa7113 status=%02x\n", i2c_readreg(&budget->i2c_adap, 0x4a, 0x1f));447448return 0;449}450451static int saa7113_setinput(struct budget_av *budget_av, int input)452{453struct budget *budget = &budget_av->budget;454455if (1 != budget_av->has_saa7113)456return -ENODEV;457458if (input == 1) {459i2c_writereg(&budget->i2c_adap, 0x4a, 0x02, 0xc7);460i2c_writereg(&budget->i2c_adap, 0x4a, 0x09, 0x80);461} else if (input == 0) {462i2c_writereg(&budget->i2c_adap, 0x4a, 0x02, 0xc0);463i2c_writereg(&budget->i2c_adap, 0x4a, 0x09, 0x00);464} else465return -EINVAL;466467budget_av->cur_input = input;468return 0;469}470471472static int philips_su1278_ty_ci_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)473{474u8 aclk = 0;475u8 bclk = 0;476u8 m1;477478aclk = 0xb5;479if (srate < 2000000)480bclk = 0x86;481else if (srate < 5000000)482bclk = 0x89;483else if (srate < 15000000)484bclk = 0x8f;485else if (srate < 45000000)486bclk = 0x95;487488m1 = 0x14;489if (srate < 4000000)490m1 = 0x10;491492stv0299_writereg(fe, 0x13, aclk);493stv0299_writereg(fe, 0x14, bclk);494stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);495stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);496stv0299_writereg(fe, 0x21, (ratio) & 0xf0);497stv0299_writereg(fe, 0x0f, 0x80 | m1);498499return 0;500}501502static int philips_su1278_ty_ci_tuner_set_params(struct dvb_frontend *fe,503struct dvb_frontend_parameters *params)504{505u32 div;506u8 buf[4];507struct budget *budget = (struct budget *) fe->dvb->priv;508struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) };509510if ((params->frequency < 950000) || (params->frequency > 2150000))511return -EINVAL;512513div = (params->frequency + (125 - 1)) / 125; // round correctly514buf[0] = (div >> 8) & 0x7f;515buf[1] = div & 0xff;516buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4;517buf[3] = 0x20;518519if (params->u.qpsk.symbol_rate < 4000000)520buf[3] |= 1;521522if (params->frequency < 1250000)523buf[3] |= 0;524else if (params->frequency < 1550000)525buf[3] |= 0x40;526else if (params->frequency < 2050000)527buf[3] |= 0x80;528else if (params->frequency < 2150000)529buf[3] |= 0xC0;530531if (fe->ops.i2c_gate_ctrl)532fe->ops.i2c_gate_ctrl(fe, 1);533if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)534return -EIO;535return 0;536}537538static u8 typhoon_cinergy1200s_inittab[] = {5390x01, 0x15,5400x02, 0x30,5410x03, 0x00,5420x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */5430x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */5440x06, 0x40, /* DAC not used, set to high impendance mode */5450x07, 0x00, /* DAC LSB */5460x08, 0x40, /* DiSEqC off */5470x09, 0x00, /* FIFO */5480x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */5490x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */5500x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */5510x10, 0x3f, // AGC2 0x3d5520x11, 0x84,5530x12, 0xb9,5540x15, 0xc9, // lock detector threshold5550x16, 0x00,5560x17, 0x00,5570x18, 0x00,5580x19, 0x00,5590x1a, 0x00,5600x1f, 0x50,5610x20, 0x00,5620x21, 0x00,5630x22, 0x00,5640x23, 0x00,5650x28, 0x00, // out imp: normal out type: parallel FEC mode:05660x29, 0x1e, // 1/2 threshold5670x2a, 0x14, // 2/3 threshold5680x2b, 0x0f, // 3/4 threshold5690x2c, 0x09, // 5/6 threshold5700x2d, 0x05, // 7/8 threshold5710x2e, 0x01,5720x31, 0x1f, // test all FECs5730x32, 0x19, // viterbi and synchro search5740x33, 0xfc, // rs control5750x34, 0x93, // error control5760x0f, 0x92,5770xff, 0xff578};579580static struct stv0299_config typhoon_config = {581.demod_address = 0x68,582.inittab = typhoon_cinergy1200s_inittab,583.mclk = 88000000UL,584.invert = 0,585.skip_reinit = 0,586.lock_output = STV0299_LOCKOUTPUT_1,587.volt13_op0_op1 = STV0299_VOLT13_OP0,588.min_delay_ms = 100,589.set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,590};591592593static struct stv0299_config cinergy_1200s_config = {594.demod_address = 0x68,595.inittab = typhoon_cinergy1200s_inittab,596.mclk = 88000000UL,597.invert = 0,598.skip_reinit = 0,599.lock_output = STV0299_LOCKOUTPUT_0,600.volt13_op0_op1 = STV0299_VOLT13_OP0,601.min_delay_ms = 100,602.set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,603};604605static struct stv0299_config cinergy_1200s_1894_0010_config = {606.demod_address = 0x68,607.inittab = typhoon_cinergy1200s_inittab,608.mclk = 88000000UL,609.invert = 1,610.skip_reinit = 0,611.lock_output = STV0299_LOCKOUTPUT_1,612.volt13_op0_op1 = STV0299_VOLT13_OP0,613.min_delay_ms = 100,614.set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,615};616617static int philips_cu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)618{619struct budget *budget = (struct budget *) fe->dvb->priv;620u8 buf[6];621struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };622int i;623624#define CU1216_IF 36125000625#define TUNER_MUL 62500626627u32 div = (params->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL;628629buf[0] = (div >> 8) & 0x7f;630buf[1] = div & 0xff;631buf[2] = 0xce;632buf[3] = (params->frequency < 150000000 ? 0x01 :633params->frequency < 445000000 ? 0x02 : 0x04);634buf[4] = 0xde;635buf[5] = 0x20;636637if (fe->ops.i2c_gate_ctrl)638fe->ops.i2c_gate_ctrl(fe, 1);639if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)640return -EIO;641642/* wait for the pll lock */643msg.flags = I2C_M_RD;644msg.len = 1;645for (i = 0; i < 20; i++) {646if (fe->ops.i2c_gate_ctrl)647fe->ops.i2c_gate_ctrl(fe, 1);648if (i2c_transfer(&budget->i2c_adap, &msg, 1) == 1 && (buf[0] & 0x40))649break;650msleep(10);651}652653/* switch the charge pump to the lower current */654msg.flags = 0;655msg.len = 2;656msg.buf = &buf[2];657buf[2] &= ~0x40;658if (fe->ops.i2c_gate_ctrl)659fe->ops.i2c_gate_ctrl(fe, 1);660if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)661return -EIO;662663return 0;664}665666static struct tda1002x_config philips_cu1216_config = {667.demod_address = 0x0c,668.invert = 1,669};670671static struct tda1002x_config philips_cu1216_config_altaddress = {672.demod_address = 0x0d,673.invert = 0,674};675676static struct tda10023_config philips_cu1216_tda10023_config = {677.demod_address = 0x0c,678.invert = 1,679};680681static int philips_tu1216_tuner_init(struct dvb_frontend *fe)682{683struct budget *budget = (struct budget *) fe->dvb->priv;684static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab };685struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) };686687// setup PLL configuration688if (fe->ops.i2c_gate_ctrl)689fe->ops.i2c_gate_ctrl(fe, 1);690if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1)691return -EIO;692msleep(1);693694return 0;695}696697static int philips_tu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)698{699struct budget *budget = (struct budget *) fe->dvb->priv;700u8 tuner_buf[4];701struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf,.len =702sizeof(tuner_buf) };703int tuner_frequency = 0;704u8 band, cp, filter;705706// determine charge pump707tuner_frequency = params->frequency + 36166000;708if (tuner_frequency < 87000000)709return -EINVAL;710else if (tuner_frequency < 130000000)711cp = 3;712else if (tuner_frequency < 160000000)713cp = 5;714else if (tuner_frequency < 200000000)715cp = 6;716else if (tuner_frequency < 290000000)717cp = 3;718else if (tuner_frequency < 420000000)719cp = 5;720else if (tuner_frequency < 480000000)721cp = 6;722else if (tuner_frequency < 620000000)723cp = 3;724else if (tuner_frequency < 830000000)725cp = 5;726else if (tuner_frequency < 895000000)727cp = 7;728else729return -EINVAL;730731// determine band732if (params->frequency < 49000000)733return -EINVAL;734else if (params->frequency < 161000000)735band = 1;736else if (params->frequency < 444000000)737band = 2;738else if (params->frequency < 861000000)739band = 4;740else741return -EINVAL;742743// setup PLL filter744switch (params->u.ofdm.bandwidth) {745case BANDWIDTH_6_MHZ:746filter = 0;747break;748749case BANDWIDTH_7_MHZ:750filter = 0;751break;752753case BANDWIDTH_8_MHZ:754filter = 1;755break;756757default:758return -EINVAL;759}760761// calculate divisor762// ((36166000+((1000000/6)/2)) + Finput)/(1000000/6)763tuner_frequency = (((params->frequency / 1000) * 6) + 217496) / 1000;764765// setup tuner buffer766tuner_buf[0] = (tuner_frequency >> 8) & 0x7f;767tuner_buf[1] = tuner_frequency & 0xff;768tuner_buf[2] = 0xca;769tuner_buf[3] = (cp << 5) | (filter << 3) | band;770771if (fe->ops.i2c_gate_ctrl)772fe->ops.i2c_gate_ctrl(fe, 1);773if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1)774return -EIO;775776msleep(1);777return 0;778}779780static int philips_tu1216_request_firmware(struct dvb_frontend *fe,781const struct firmware **fw, char *name)782{783struct budget *budget = (struct budget *) fe->dvb->priv;784785return request_firmware(fw, name, &budget->dev->pci->dev);786}787788static struct tda1004x_config philips_tu1216_config = {789790.demod_address = 0x8,791.invert = 1,792.invert_oclk = 1,793.xtal_freq = TDA10046_XTAL_4M,794.agc_config = TDA10046_AGC_DEFAULT,795.if_freq = TDA10046_FREQ_3617,796.request_firmware = philips_tu1216_request_firmware,797};798799static u8 philips_sd1878_inittab[] = {8000x01, 0x15,8010x02, 0x30,8020x03, 0x00,8030x04, 0x7d,8040x05, 0x35,8050x06, 0x40,8060x07, 0x00,8070x08, 0x43,8080x09, 0x02,8090x0C, 0x51,8100x0D, 0x82,8110x0E, 0x23,8120x10, 0x3f,8130x11, 0x84,8140x12, 0xb9,8150x15, 0xc9,8160x16, 0x19,8170x17, 0x8c,8180x18, 0x59,8190x19, 0xf8,8200x1a, 0xfe,8210x1c, 0x7f,8220x1d, 0x00,8230x1e, 0x00,8240x1f, 0x50,8250x20, 0x00,8260x21, 0x00,8270x22, 0x00,8280x23, 0x00,8290x28, 0x00,8300x29, 0x28,8310x2a, 0x14,8320x2b, 0x0f,8330x2c, 0x09,8340x2d, 0x09,8350x31, 0x1f,8360x32, 0x19,8370x33, 0xfc,8380x34, 0x93,8390xff, 0xff840};841842static int philips_sd1878_ci_set_symbol_rate(struct dvb_frontend *fe,843u32 srate, u32 ratio)844{845u8 aclk = 0;846u8 bclk = 0;847u8 m1;848849aclk = 0xb5;850if (srate < 2000000)851bclk = 0x86;852else if (srate < 5000000)853bclk = 0x89;854else if (srate < 15000000)855bclk = 0x8f;856else if (srate < 45000000)857bclk = 0x95;858859m1 = 0x14;860if (srate < 4000000)861m1 = 0x10;862863stv0299_writereg(fe, 0x0e, 0x23);864stv0299_writereg(fe, 0x0f, 0x94);865stv0299_writereg(fe, 0x10, 0x39);866stv0299_writereg(fe, 0x13, aclk);867stv0299_writereg(fe, 0x14, bclk);868stv0299_writereg(fe, 0x15, 0xc9);869stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);870stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);871stv0299_writereg(fe, 0x21, (ratio) & 0xf0);872stv0299_writereg(fe, 0x0f, 0x80 | m1);873874return 0;875}876877static struct stv0299_config philips_sd1878_config = {878.demod_address = 0x68,879.inittab = philips_sd1878_inittab,880.mclk = 88000000UL,881.invert = 0,882.skip_reinit = 0,883.lock_output = STV0299_LOCKOUTPUT_1,884.volt13_op0_op1 = STV0299_VOLT13_OP0,885.min_delay_ms = 100,886.set_symbol_rate = philips_sd1878_ci_set_symbol_rate,887};888889/* KNC1 DVB-S (STB0899) Inittab */890static const struct stb0899_s1_reg knc1_stb0899_s1_init_1[] = {891892{ STB0899_DEV_ID , 0x81 },893{ STB0899_DISCNTRL1 , 0x32 },894{ STB0899_DISCNTRL2 , 0x80 },895{ STB0899_DISRX_ST0 , 0x04 },896{ STB0899_DISRX_ST1 , 0x00 },897{ STB0899_DISPARITY , 0x00 },898{ STB0899_DISFIFO , 0x00 },899{ STB0899_DISSTATUS , 0x20 },900{ STB0899_DISF22 , 0x8c },901{ STB0899_DISF22RX , 0x9a },902{ STB0899_SYSREG , 0x0b },903{ STB0899_ACRPRESC , 0x11 },904{ STB0899_ACRDIV1 , 0x0a },905{ STB0899_ACRDIV2 , 0x05 },906{ STB0899_DACR1 , 0x00 },907{ STB0899_DACR2 , 0x00 },908{ STB0899_OUTCFG , 0x00 },909{ STB0899_MODECFG , 0x00 },910{ STB0899_IRQSTATUS_3 , 0x30 },911{ STB0899_IRQSTATUS_2 , 0x00 },912{ STB0899_IRQSTATUS_1 , 0x00 },913{ STB0899_IRQSTATUS_0 , 0x00 },914{ STB0899_IRQMSK_3 , 0xf3 },915{ STB0899_IRQMSK_2 , 0xfc },916{ STB0899_IRQMSK_1 , 0xff },917{ STB0899_IRQMSK_0 , 0xff },918{ STB0899_IRQCFG , 0x00 },919{ STB0899_I2CCFG , 0x88 },920{ STB0899_I2CRPT , 0x58 }, /* Repeater=8, Stop=disabled */921{ STB0899_IOPVALUE5 , 0x00 },922{ STB0899_IOPVALUE4 , 0x20 },923{ STB0899_IOPVALUE3 , 0xc9 },924{ STB0899_IOPVALUE2 , 0x90 },925{ STB0899_IOPVALUE1 , 0x40 },926{ STB0899_IOPVALUE0 , 0x00 },927{ STB0899_GPIO00CFG , 0x82 },928{ STB0899_GPIO01CFG , 0x82 },929{ STB0899_GPIO02CFG , 0x82 },930{ STB0899_GPIO03CFG , 0x82 },931{ STB0899_GPIO04CFG , 0x82 },932{ STB0899_GPIO05CFG , 0x82 },933{ STB0899_GPIO06CFG , 0x82 },934{ STB0899_GPIO07CFG , 0x82 },935{ STB0899_GPIO08CFG , 0x82 },936{ STB0899_GPIO09CFG , 0x82 },937{ STB0899_GPIO10CFG , 0x82 },938{ STB0899_GPIO11CFG , 0x82 },939{ STB0899_GPIO12CFG , 0x82 },940{ STB0899_GPIO13CFG , 0x82 },941{ STB0899_GPIO14CFG , 0x82 },942{ STB0899_GPIO15CFG , 0x82 },943{ STB0899_GPIO16CFG , 0x82 },944{ STB0899_GPIO17CFG , 0x82 },945{ STB0899_GPIO18CFG , 0x82 },946{ STB0899_GPIO19CFG , 0x82 },947{ STB0899_GPIO20CFG , 0x82 },948{ STB0899_SDATCFG , 0xb8 },949{ STB0899_SCLTCFG , 0xba },950{ STB0899_AGCRFCFG , 0x08 }, /* 0x1c */951{ STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */952{ STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */953{ STB0899_DIRCLKCFG , 0x82 },954{ STB0899_CLKOUT27CFG , 0x7e },955{ STB0899_STDBYCFG , 0x82 },956{ STB0899_CS0CFG , 0x82 },957{ STB0899_CS1CFG , 0x82 },958{ STB0899_DISEQCOCFG , 0x20 },959{ STB0899_GPIO32CFG , 0x82 },960{ STB0899_GPIO33CFG , 0x82 },961{ STB0899_GPIO34CFG , 0x82 },962{ STB0899_GPIO35CFG , 0x82 },963{ STB0899_GPIO36CFG , 0x82 },964{ STB0899_GPIO37CFG , 0x82 },965{ STB0899_GPIO38CFG , 0x82 },966{ STB0899_GPIO39CFG , 0x82 },967{ STB0899_NCOARSE , 0x15 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */968{ STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */969{ STB0899_FILTCTRL , 0x00 },970{ STB0899_SYSCTRL , 0x00 },971{ STB0899_STOPCLK1 , 0x20 },972{ STB0899_STOPCLK2 , 0x00 },973{ STB0899_INTBUFSTATUS , 0x00 },974{ STB0899_INTBUFCTRL , 0x0a },975{ 0xffff , 0xff },976};977978static const struct stb0899_s1_reg knc1_stb0899_s1_init_3[] = {979{ STB0899_DEMOD , 0x00 },980{ STB0899_RCOMPC , 0xc9 },981{ STB0899_AGC1CN , 0x41 },982{ STB0899_AGC1REF , 0x08 },983{ STB0899_RTC , 0x7a },984{ STB0899_TMGCFG , 0x4e },985{ STB0899_AGC2REF , 0x33 },986{ STB0899_TLSR , 0x84 },987{ STB0899_CFD , 0xee },988{ STB0899_ACLC , 0x87 },989{ STB0899_BCLC , 0x94 },990{ STB0899_EQON , 0x41 },991{ STB0899_LDT , 0xdd },992{ STB0899_LDT2 , 0xc9 },993{ STB0899_EQUALREF , 0xb4 },994{ STB0899_TMGRAMP , 0x10 },995{ STB0899_TMGTHD , 0x30 },996{ STB0899_IDCCOMP , 0xfb },997{ STB0899_QDCCOMP , 0x03 },998{ STB0899_POWERI , 0x3b },999{ STB0899_POWERQ , 0x3d },1000{ STB0899_RCOMP , 0x81 },1001{ STB0899_AGCIQIN , 0x80 },1002{ STB0899_AGC2I1 , 0x04 },1003{ STB0899_AGC2I2 , 0xf5 },1004{ STB0899_TLIR , 0x25 },1005{ STB0899_RTF , 0x80 },1006{ STB0899_DSTATUS , 0x00 },1007{ STB0899_LDI , 0xca },1008{ STB0899_CFRM , 0xf1 },1009{ STB0899_CFRL , 0xf3 },1010{ STB0899_NIRM , 0x2a },1011{ STB0899_NIRL , 0x05 },1012{ STB0899_ISYMB , 0x17 },1013{ STB0899_QSYMB , 0xfa },1014{ STB0899_SFRH , 0x2f },1015{ STB0899_SFRM , 0x68 },1016{ STB0899_SFRL , 0x40 },1017{ STB0899_SFRUPH , 0x2f },1018{ STB0899_SFRUPM , 0x68 },1019{ STB0899_SFRUPL , 0x40 },1020{ STB0899_EQUAI1 , 0xfd },1021{ STB0899_EQUAQ1 , 0x04 },1022{ STB0899_EQUAI2 , 0x0f },1023{ STB0899_EQUAQ2 , 0xff },1024{ STB0899_EQUAI3 , 0xdf },1025{ STB0899_EQUAQ3 , 0xfa },1026{ STB0899_EQUAI4 , 0x37 },1027{ STB0899_EQUAQ4 , 0x0d },1028{ STB0899_EQUAI5 , 0xbd },1029{ STB0899_EQUAQ5 , 0xf7 },1030{ STB0899_DSTATUS2 , 0x00 },1031{ STB0899_VSTATUS , 0x00 },1032{ STB0899_VERROR , 0xff },1033{ STB0899_IQSWAP , 0x2a },1034{ STB0899_ECNT1M , 0x00 },1035{ STB0899_ECNT1L , 0x00 },1036{ STB0899_ECNT2M , 0x00 },1037{ STB0899_ECNT2L , 0x00 },1038{ STB0899_ECNT3M , 0x00 },1039{ STB0899_ECNT3L , 0x00 },1040{ STB0899_FECAUTO1 , 0x06 },1041{ STB0899_FECM , 0x01 },1042{ STB0899_VTH12 , 0xf0 },1043{ STB0899_VTH23 , 0xa0 },1044{ STB0899_VTH34 , 0x78 },1045{ STB0899_VTH56 , 0x4e },1046{ STB0899_VTH67 , 0x48 },1047{ STB0899_VTH78 , 0x38 },1048{ STB0899_PRVIT , 0xff },1049{ STB0899_VITSYNC , 0x19 },1050{ STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */1051{ STB0899_TSULC , 0x42 },1052{ STB0899_RSLLC , 0x40 },1053{ STB0899_TSLPL , 0x12 },1054{ STB0899_TSCFGH , 0x0c },1055{ STB0899_TSCFGM , 0x00 },1056{ STB0899_TSCFGL , 0x0c },1057{ STB0899_TSOUT , 0x4d }, /* 0x0d for CAM */1058{ STB0899_RSSYNCDEL , 0x00 },1059{ STB0899_TSINHDELH , 0x02 },1060{ STB0899_TSINHDELM , 0x00 },1061{ STB0899_TSINHDELL , 0x00 },1062{ STB0899_TSLLSTKM , 0x00 },1063{ STB0899_TSLLSTKL , 0x00 },1064{ STB0899_TSULSTKM , 0x00 },1065{ STB0899_TSULSTKL , 0xab },1066{ STB0899_PCKLENUL , 0x00 },1067{ STB0899_PCKLENLL , 0xcc },1068{ STB0899_RSPCKLEN , 0xcc },1069{ STB0899_TSSTATUS , 0x80 },1070{ STB0899_ERRCTRL1 , 0xb6 },1071{ STB0899_ERRCTRL2 , 0x96 },1072{ STB0899_ERRCTRL3 , 0x89 },1073{ STB0899_DMONMSK1 , 0x27 },1074{ STB0899_DMONMSK0 , 0x03 },1075{ STB0899_DEMAPVIT , 0x5c },1076{ STB0899_PLPARM , 0x1f },1077{ STB0899_PDELCTRL , 0x48 },1078{ STB0899_PDELCTRL2 , 0x00 },1079{ STB0899_BBHCTRL1 , 0x00 },1080{ STB0899_BBHCTRL2 , 0x00 },1081{ STB0899_HYSTTHRESH , 0x77 },1082{ STB0899_MATCSTM , 0x00 },1083{ STB0899_MATCSTL , 0x00 },1084{ STB0899_UPLCSTM , 0x00 },1085{ STB0899_UPLCSTL , 0x00 },1086{ STB0899_DFLCSTM , 0x00 },1087{ STB0899_DFLCSTL , 0x00 },1088{ STB0899_SYNCCST , 0x00 },1089{ STB0899_SYNCDCSTM , 0x00 },1090{ STB0899_SYNCDCSTL , 0x00 },1091{ STB0899_ISI_ENTRY , 0x00 },1092{ STB0899_ISI_BIT_EN , 0x00 },1093{ STB0899_MATSTRM , 0x00 },1094{ STB0899_MATSTRL , 0x00 },1095{ STB0899_UPLSTRM , 0x00 },1096{ STB0899_UPLSTRL , 0x00 },1097{ STB0899_DFLSTRM , 0x00 },1098{ STB0899_DFLSTRL , 0x00 },1099{ STB0899_SYNCSTR , 0x00 },1100{ STB0899_SYNCDSTRM , 0x00 },1101{ STB0899_SYNCDSTRL , 0x00 },1102{ STB0899_CFGPDELSTATUS1 , 0x10 },1103{ STB0899_CFGPDELSTATUS2 , 0x00 },1104{ STB0899_BBFERRORM , 0x00 },1105{ STB0899_BBFERRORL , 0x00 },1106{ STB0899_UPKTERRORM , 0x00 },1107{ STB0899_UPKTERRORL , 0x00 },1108{ 0xffff , 0xff },1109};11101111/* STB0899 demodulator config for the KNC1 and clones */1112static struct stb0899_config knc1_dvbs2_config = {1113.init_dev = knc1_stb0899_s1_init_1,1114.init_s2_demod = stb0899_s2_init_2,1115.init_s1_demod = knc1_stb0899_s1_init_3,1116.init_s2_fec = stb0899_s2_init_4,1117.init_tst = stb0899_s1_init_5,11181119.postproc = NULL,11201121.demod_address = 0x68,1122// .ts_output_mode = STB0899_OUT_PARALLEL, /* types = SERIAL/PARALLEL */1123.block_sync_mode = STB0899_SYNC_FORCED, /* DSS, SYNC_FORCED/UNSYNCED */1124// .ts_pfbit_toggle = STB0899_MPEG_NORMAL, /* DirecTV, MPEG toggling seq */11251126.xtal_freq = 27000000,1127.inversion = IQ_SWAP_OFF, /* 1 */11281129.lo_clk = 76500000,1130.hi_clk = 90000000,11311132.esno_ave = STB0899_DVBS2_ESNO_AVE,1133.esno_quant = STB0899_DVBS2_ESNO_QUANT,1134.avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE,1135.avframes_fine = STB0899_DVBS2_AVFRAMES_FINE,1136.miss_threshold = STB0899_DVBS2_MISS_THRESHOLD,1137.uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ,1138.uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK,1139.uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF,1140.sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT,11411142.btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS,1143.btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET,1144.crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS,1145.ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER,11461147.tuner_get_frequency = tda8261_get_frequency,1148.tuner_set_frequency = tda8261_set_frequency,1149.tuner_set_bandwidth = NULL,1150.tuner_get_bandwidth = tda8261_get_bandwidth,1151.tuner_set_rfsiggain = NULL1152};11531154/*1155* SD1878/SHA tuner config1156* 1F, Single I/P, Horizontal mount, High Sensitivity1157*/1158static const struct tda8261_config sd1878c_config = {1159// .name = "SD1878/SHA",1160.addr = 0x60,1161.step_size = TDA8261_STEP_1000 /* kHz */1162};11631164static u8 read_pwm(struct budget_av *budget_av)1165{1166u8 b = 0xff;1167u8 pwm;1168struct i2c_msg msg[] = { {.addr = 0x50,.flags = 0,.buf = &b,.len = 1},1169{.addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1}1170};11711172if ((i2c_transfer(&budget_av->budget.i2c_adap, msg, 2) != 2)1173|| (pwm == 0xff))1174pwm = 0x48;11751176return pwm;1177}11781179#define SUBID_DVBS_KNC1 0x00101180#define SUBID_DVBS_KNC1_PLUS 0x00111181#define SUBID_DVBS_TYPHOON 0x4f561182#define SUBID_DVBS_CINERGY1200 0x11541183#define SUBID_DVBS_CYNERGY1200N 0x11551184#define SUBID_DVBS_TV_STAR 0x00141185#define SUBID_DVBS_TV_STAR_PLUS_X4 0x00151186#define SUBID_DVBS_TV_STAR_CI 0x00161187#define SUBID_DVBS2_KNC1 0x00181188#define SUBID_DVBS2_KNC1_OEM 0x00191189#define SUBID_DVBS_EASYWATCH_1 0x001a1190#define SUBID_DVBS_EASYWATCH_2 0x001b1191#define SUBID_DVBS2_EASYWATCH 0x001d1192#define SUBID_DVBS_EASYWATCH 0x001e11931194#define SUBID_DVBC_EASYWATCH 0x002a1195#define SUBID_DVBC_EASYWATCH_MK3 0x002c1196#define SUBID_DVBC_KNC1 0x00201197#define SUBID_DVBC_KNC1_PLUS 0x00211198#define SUBID_DVBC_KNC1_MK3 0x00221199#define SUBID_DVBC_KNC1_PLUS_MK3 0x00231200#define SUBID_DVBC_CINERGY1200 0x11561201#define SUBID_DVBC_CINERGY1200_MK3 0x117612021203#define SUBID_DVBT_EASYWATCH 0x003a1204#define SUBID_DVBT_KNC1_PLUS 0x00311205#define SUBID_DVBT_KNC1 0x00301206#define SUBID_DVBT_CINERGY1200 0x115712071208static void frontend_init(struct budget_av *budget_av)1209{1210struct saa7146_dev * saa = budget_av->budget.dev;1211struct dvb_frontend * fe = NULL;12121213/* Enable / PowerON Frontend */1214saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO);12151216/* Wait for PowerON */1217msleep(100);12181219/* additional setup necessary for the PLUS cards */1220switch (saa->pci->subsystem_device) {1221case SUBID_DVBS_KNC1_PLUS:1222case SUBID_DVBC_KNC1_PLUS:1223case SUBID_DVBT_KNC1_PLUS:1224case SUBID_DVBC_EASYWATCH:1225case SUBID_DVBC_KNC1_PLUS_MK3:1226case SUBID_DVBS2_KNC1:1227case SUBID_DVBS2_KNC1_OEM:1228case SUBID_DVBS2_EASYWATCH:1229saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTHI);1230break;1231}12321233switch (saa->pci->subsystem_device) {12341235case SUBID_DVBS_KNC1:1236/*1237* maybe that setting is needed for other dvb-s cards as well,1238* but so far it has been only confirmed for this type1239*/1240budget_av->reinitialise_demod = 1;1241/* fall through */1242case SUBID_DVBS_KNC1_PLUS:1243case SUBID_DVBS_EASYWATCH_1:1244if (saa->pci->subsystem_vendor == 0x1894) {1245fe = dvb_attach(stv0299_attach, &cinergy_1200s_1894_0010_config,1246&budget_av->budget.i2c_adap);1247if (fe) {1248dvb_attach(tua6100_attach, fe, 0x60, &budget_av->budget.i2c_adap);1249}1250} else {1251fe = dvb_attach(stv0299_attach, &typhoon_config,1252&budget_av->budget.i2c_adap);1253if (fe) {1254fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;1255}1256}1257break;12581259case SUBID_DVBS_TV_STAR:1260case SUBID_DVBS_TV_STAR_PLUS_X4:1261case SUBID_DVBS_TV_STAR_CI:1262case SUBID_DVBS_CYNERGY1200N:1263case SUBID_DVBS_EASYWATCH:1264case SUBID_DVBS_EASYWATCH_2:1265fe = dvb_attach(stv0299_attach, &philips_sd1878_config,1266&budget_av->budget.i2c_adap);1267if (fe) {1268dvb_attach(dvb_pll_attach, fe, 0x60,1269&budget_av->budget.i2c_adap,1270DVB_PLL_PHILIPS_SD1878_TDA8261);1271}1272break;12731274case SUBID_DVBS_TYPHOON:1275fe = dvb_attach(stv0299_attach, &typhoon_config,1276&budget_av->budget.i2c_adap);1277if (fe) {1278fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;1279}1280break;1281case SUBID_DVBS2_KNC1:1282case SUBID_DVBS2_KNC1_OEM:1283case SUBID_DVBS2_EASYWATCH:1284budget_av->reinitialise_demod = 1;1285if ((fe = dvb_attach(stb0899_attach, &knc1_dvbs2_config, &budget_av->budget.i2c_adap)))1286dvb_attach(tda8261_attach, fe, &sd1878c_config, &budget_av->budget.i2c_adap);12871288break;1289case SUBID_DVBS_CINERGY1200:1290fe = dvb_attach(stv0299_attach, &cinergy_1200s_config,1291&budget_av->budget.i2c_adap);1292if (fe) {1293fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;1294}1295break;12961297case SUBID_DVBC_KNC1:1298case SUBID_DVBC_KNC1_PLUS:1299case SUBID_DVBC_CINERGY1200:1300case SUBID_DVBC_EASYWATCH:1301budget_av->reinitialise_demod = 1;1302budget_av->budget.dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240;1303fe = dvb_attach(tda10021_attach, &philips_cu1216_config,1304&budget_av->budget.i2c_adap,1305read_pwm(budget_av));1306if (fe == NULL)1307fe = dvb_attach(tda10021_attach, &philips_cu1216_config_altaddress,1308&budget_av->budget.i2c_adap,1309read_pwm(budget_av));1310if (fe) {1311fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params;1312}1313break;13141315case SUBID_DVBC_EASYWATCH_MK3:1316case SUBID_DVBC_CINERGY1200_MK3:1317case SUBID_DVBC_KNC1_MK3:1318case SUBID_DVBC_KNC1_PLUS_MK3:1319budget_av->reinitialise_demod = 1;1320budget_av->budget.dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240;1321fe = dvb_attach(tda10023_attach,1322&philips_cu1216_tda10023_config,1323&budget_av->budget.i2c_adap,1324read_pwm(budget_av));1325if (fe) {1326fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params;1327}1328break;13291330case SUBID_DVBT_EASYWATCH:1331case SUBID_DVBT_KNC1:1332case SUBID_DVBT_KNC1_PLUS:1333case SUBID_DVBT_CINERGY1200:1334budget_av->reinitialise_demod = 1;1335fe = dvb_attach(tda10046_attach, &philips_tu1216_config,1336&budget_av->budget.i2c_adap);1337if (fe) {1338fe->ops.tuner_ops.init = philips_tu1216_tuner_init;1339fe->ops.tuner_ops.set_params = philips_tu1216_tuner_set_params;1340}1341break;1342}13431344if (fe == NULL) {1345printk(KERN_ERR "budget-av: A frontend driver was not found "1346"for device [%04x:%04x] subsystem [%04x:%04x]\n",1347saa->pci->vendor,1348saa->pci->device,1349saa->pci->subsystem_vendor,1350saa->pci->subsystem_device);1351return;1352}13531354budget_av->budget.dvb_frontend = fe;13551356if (dvb_register_frontend(&budget_av->budget.dvb_adapter,1357budget_av->budget.dvb_frontend)) {1358printk(KERN_ERR "budget-av: Frontend registration failed!\n");1359dvb_frontend_detach(budget_av->budget.dvb_frontend);1360budget_av->budget.dvb_frontend = NULL;1361}1362}136313641365static void budget_av_irq(struct saa7146_dev *dev, u32 * isr)1366{1367struct budget_av *budget_av = (struct budget_av *) dev->ext_priv;13681369dprintk(8, "dev: %p, budget_av: %p\n", dev, budget_av);13701371if (*isr & MASK_10)1372ttpci_budget_irq10_handler(dev, isr);1373}13741375static int budget_av_detach(struct saa7146_dev *dev)1376{1377struct budget_av *budget_av = (struct budget_av *) dev->ext_priv;1378int err;13791380dprintk(2, "dev: %p\n", dev);13811382if (1 == budget_av->has_saa7113) {1383saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTLO);13841385msleep(200);13861387saa7146_unregister_device(&budget_av->vd, dev);13881389saa7146_vv_release(dev);1390}13911392if (budget_av->budget.ci_present)1393ciintf_deinit(budget_av);13941395if (budget_av->budget.dvb_frontend != NULL) {1396dvb_unregister_frontend(budget_av->budget.dvb_frontend);1397dvb_frontend_detach(budget_av->budget.dvb_frontend);1398}1399err = ttpci_budget_deinit(&budget_av->budget);14001401kfree(budget_av);14021403return err;1404}14051406#define KNC1_INPUTS 21407static struct v4l2_input knc1_inputs[KNC1_INPUTS] = {1408{ 0, "Composite", V4L2_INPUT_TYPE_TUNER, 1, 0,1409V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },1410{ 1, "S-Video", V4L2_INPUT_TYPE_CAMERA, 2, 0,1411V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },1412};14131414static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)1415{1416dprintk(1, "VIDIOC_ENUMINPUT %d.\n", i->index);1417if (i->index >= KNC1_INPUTS)1418return -EINVAL;1419memcpy(i, &knc1_inputs[i->index], sizeof(struct v4l2_input));1420return 0;1421}14221423static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)1424{1425struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;1426struct budget_av *budget_av = (struct budget_av *)dev->ext_priv;14271428*i = budget_av->cur_input;14291430dprintk(1, "VIDIOC_G_INPUT %d.\n", *i);1431return 0;1432}14331434static int vidioc_s_input(struct file *file, void *fh, unsigned int input)1435{1436struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;1437struct budget_av *budget_av = (struct budget_av *)dev->ext_priv;14381439dprintk(1, "VIDIOC_S_INPUT %d.\n", input);1440return saa7113_setinput(budget_av, input);1441}14421443static struct saa7146_ext_vv vv_data;14441445static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)1446{1447struct budget_av *budget_av;1448u8 *mac;1449int err;14501451dprintk(2, "dev: %p\n", dev);14521453if (!(budget_av = kzalloc(sizeof(struct budget_av), GFP_KERNEL)))1454return -ENOMEM;14551456budget_av->has_saa7113 = 0;1457budget_av->budget.ci_present = 0;14581459dev->ext_priv = budget_av;14601461err = ttpci_budget_init(&budget_av->budget, dev, info, THIS_MODULE,1462adapter_nr);1463if (err) {1464kfree(budget_av);1465return err;1466}14671468/* knc1 initialization */1469saa7146_write(dev, DD1_STREAM_B, 0x04000000);1470saa7146_write(dev, DD1_INIT, 0x07000600);1471saa7146_write(dev, MC2, MASK_09 | MASK_25 | MASK_10 | MASK_26);14721473if (saa7113_init(budget_av) == 0) {1474budget_av->has_saa7113 = 1;14751476if (0 != saa7146_vv_init(dev, &vv_data)) {1477/* fixme: proper cleanup here */1478ERR(("cannot init vv subsystem.\n"));1479return err;1480}1481vv_data.ops.vidioc_enum_input = vidioc_enum_input;1482vv_data.ops.vidioc_g_input = vidioc_g_input;1483vv_data.ops.vidioc_s_input = vidioc_s_input;14841485if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_GRABBER))) {1486/* fixme: proper cleanup here */1487ERR(("cannot register capture v4l2 device.\n"));1488saa7146_vv_release(dev);1489return err;1490}14911492/* beware: this modifies dev->vv ... */1493saa7146_set_hps_source_and_sync(dev, SAA7146_HPS_SOURCE_PORT_A,1494SAA7146_HPS_SYNC_PORT_A);14951496saa7113_setinput(budget_av, 0);1497}14981499/* fixme: find some sane values here... */1500saa7146_write(dev, PCI_BT_V1, 0x1c00101f);15011502mac = budget_av->budget.dvb_adapter.proposed_mac;1503if (i2c_readregs(&budget_av->budget.i2c_adap, 0xa0, 0x30, mac, 6)) {1504printk(KERN_ERR "KNC1-%d: Could not read MAC from KNC1 card\n",1505budget_av->budget.dvb_adapter.num);1506memset(mac, 0, 6);1507} else {1508printk(KERN_INFO "KNC1-%d: MAC addr = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",1509budget_av->budget.dvb_adapter.num,1510mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);1511}15121513budget_av->budget.dvb_adapter.priv = budget_av;1514frontend_init(budget_av);1515ciintf_init(budget_av);15161517ttpci_budget_init_hooks(&budget_av->budget);15181519return 0;1520}15211522static struct saa7146_standard standard[] = {1523{.name = "PAL",.id = V4L2_STD_PAL,1524.v_offset = 0x17,.v_field = 288,1525.h_offset = 0x14,.h_pixels = 680,1526.v_max_out = 576,.h_max_out = 768 },15271528{.name = "NTSC",.id = V4L2_STD_NTSC,1529.v_offset = 0x16,.v_field = 240,1530.h_offset = 0x06,.h_pixels = 708,1531.v_max_out = 480,.h_max_out = 640, },1532};15331534static struct saa7146_ext_vv vv_data = {1535.inputs = 2,1536.capabilities = 0, // perhaps later: V4L2_CAP_VBI_CAPTURE, but that need tweaking with the saa71131537.flags = 0,1538.stds = &standard[0],1539.num_stds = ARRAY_SIZE(standard),1540};15411542static struct saa7146_extension budget_extension;15431544MAKE_BUDGET_INFO(knc1s, "KNC1 DVB-S", BUDGET_KNC1S);1545MAKE_BUDGET_INFO(knc1s2,"KNC1 DVB-S2", BUDGET_KNC1S2);1546MAKE_BUDGET_INFO(sates2,"Satelco EasyWatch DVB-S2", BUDGET_KNC1S2);1547MAKE_BUDGET_INFO(knc1c, "KNC1 DVB-C", BUDGET_KNC1C);1548MAKE_BUDGET_INFO(knc1t, "KNC1 DVB-T", BUDGET_KNC1T);1549MAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB-S", BUDGET_TVSTAR);1550MAKE_BUDGET_INFO(satewpls, "Satelco EasyWatch DVB-S light", BUDGET_TVSTAR);1551MAKE_BUDGET_INFO(satewpls1, "Satelco EasyWatch DVB-S light", BUDGET_KNC1S);1552MAKE_BUDGET_INFO(satewps, "Satelco EasyWatch DVB-S", BUDGET_KNC1S);1553MAKE_BUDGET_INFO(satewplc, "Satelco EasyWatch DVB-C", BUDGET_KNC1CP);1554MAKE_BUDGET_INFO(satewcmk3, "Satelco EasyWatch DVB-C MK3", BUDGET_KNC1C_MK3);1555MAKE_BUDGET_INFO(satewt, "Satelco EasyWatch DVB-T", BUDGET_KNC1T);1556MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP);1557MAKE_BUDGET_INFO(knc1spx4, "KNC1 DVB-S Plus X4", BUDGET_KNC1SP);1558MAKE_BUDGET_INFO(knc1cp, "KNC1 DVB-C Plus", BUDGET_KNC1CP);1559MAKE_BUDGET_INFO(knc1cmk3, "KNC1 DVB-C MK3", BUDGET_KNC1C_MK3);1560MAKE_BUDGET_INFO(knc1cpmk3, "KNC1 DVB-C Plus MK3", BUDGET_KNC1CP_MK3);1561MAKE_BUDGET_INFO(knc1tp, "KNC1 DVB-T Plus", BUDGET_KNC1TP);1562MAKE_BUDGET_INFO(cin1200s, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S);1563MAKE_BUDGET_INFO(cin1200sn, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S);1564MAKE_BUDGET_INFO(cin1200c, "Terratec Cinergy 1200 DVB-C", BUDGET_CIN1200C);1565MAKE_BUDGET_INFO(cin1200cmk3, "Terratec Cinergy 1200 DVB-C MK3", BUDGET_CIN1200C_MK3);1566MAKE_BUDGET_INFO(cin1200t, "Terratec Cinergy 1200 DVB-T", BUDGET_CIN1200T);15671568static struct pci_device_id pci_tbl[] = {1569MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x4f56),1570MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x0010),1571MAKE_EXTENSION_PCI(knc1s, 0x1894, 0x0010),1572MAKE_EXTENSION_PCI(knc1sp, 0x1131, 0x0011),1573MAKE_EXTENSION_PCI(knc1sp, 0x1894, 0x0011),1574MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0014),1575MAKE_EXTENSION_PCI(knc1spx4, 0x1894, 0x0015),1576MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016),1577MAKE_EXTENSION_PCI(knc1s2, 0x1894, 0x0018),1578MAKE_EXTENSION_PCI(knc1s2, 0x1894, 0x0019),1579MAKE_EXTENSION_PCI(sates2, 0x1894, 0x001d),1580MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e),1581MAKE_EXTENSION_PCI(satewpls1, 0x1894, 0x001a),1582MAKE_EXTENSION_PCI(satewps, 0x1894, 0x001b),1583MAKE_EXTENSION_PCI(satewplc, 0x1894, 0x002a),1584MAKE_EXTENSION_PCI(satewcmk3, 0x1894, 0x002c),1585MAKE_EXTENSION_PCI(satewt, 0x1894, 0x003a),1586MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020),1587MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021),1588MAKE_EXTENSION_PCI(knc1cmk3, 0x1894, 0x0022),1589MAKE_EXTENSION_PCI(knc1cpmk3, 0x1894, 0x0023),1590MAKE_EXTENSION_PCI(knc1t, 0x1894, 0x0030),1591MAKE_EXTENSION_PCI(knc1tp, 0x1894, 0x0031),1592MAKE_EXTENSION_PCI(cin1200s, 0x153b, 0x1154),1593MAKE_EXTENSION_PCI(cin1200sn, 0x153b, 0x1155),1594MAKE_EXTENSION_PCI(cin1200c, 0x153b, 0x1156),1595MAKE_EXTENSION_PCI(cin1200cmk3, 0x153b, 0x1176),1596MAKE_EXTENSION_PCI(cin1200t, 0x153b, 0x1157),1597{1598.vendor = 0,1599}1600};16011602MODULE_DEVICE_TABLE(pci, pci_tbl);16031604static struct saa7146_extension budget_extension = {1605.name = "budget_av",1606.flags = SAA7146_USE_I2C_IRQ,16071608.pci_tbl = pci_tbl,16091610.module = THIS_MODULE,1611.attach = budget_av_attach,1612.detach = budget_av_detach,16131614.irq_mask = MASK_10,1615.irq_func = budget_av_irq,1616};16171618static int __init budget_av_init(void)1619{1620return saa7146_register_extension(&budget_extension);1621}16221623static void __exit budget_av_exit(void)1624{1625saa7146_unregister_extension(&budget_extension);1626}16271628module_init(budget_av_init);1629module_exit(budget_av_exit);16301631MODULE_LICENSE("GPL");1632MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, Michael Hunold, others");1633MODULE_DESCRIPTION("driver for the SAA7146 based so-called "1634"budget PCI DVB w/ analog input and CI-module (e.g. the KNC cards)");163516361637